十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OHIF 3.10 到 3.11 迁移指南:基于 `promptHydrationDialog` 与 `hydrateSecondaryDisplaySet` 命令的新版 Hydration 体系

OHIF 3.10 到 3.11 迁移指南:基于 `promptHydrationDialog` 与 `hydrateSecondaryDisplaySet` 命令的新版 Hydration 体系 OHIF 3.10 到 3.11 迁移指南基于promptHydrationDialog与hydrateSecondaryDisplaySet命令的新版 Hydration 体系【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers导读本文面向从 OHIF 3.10 升级到 3.11 的开发者聚焦本版本中最重要的架构变化之一——Hydration水合机制的重构原先分散在各扩展中、各自维护一套 Promise 与对话框逻辑的promptHydrateSEG/promptHydrateRT提示函数被统一收敛到ohif/extension-cornerstone的通用工具utils.promptHydrationDialog而真正执行水合的动作则改为由hydrateSecondaryDisplaySet命令统一驱动。读完本文你将掌握 3.11 中 SEG、RTSTRUCT、SR 三类二次显示集secondary display set水合提示与执行的新调用链、对话框可定制机制、以及如何把存量 3.10 代码迁移到新 API。背景3.11 的 Hydration 体系为什么重构在 3.10 及更早版本中SEG分割与 RTSTRUCT放疗结构的水合提示逻辑存在大量重复代码每个扩展cornerstone-dicom-seg、cornerstone-dicom-rt各自定义了一套RESPONSE常量、各自实现_askHydrate对话框 Promise、各自处理视口交互与回调。这不仅造成代码重复也让是否弹窗、弹什么文案、确认后执行什么这些行为难以在应用层统一定制。3.11 的改动方向清晰可见对话框逻辑下沉为通用工具promptHydrateSEG与promptHydrateRT改为薄封装内部统一委托给ohif/extension-cornerstone导出的utils.promptHydrationDialog参见 promptHydrationDialog.ts执行动作命令化真正的水合动作不再由各扩展自行编写回调闭包而是普遍通过hydrateSecondaryDisplaySet命令触发参见 commandsModule.ts。这一设计让提示与执行解耦提示层只负责询问用户并返回决策执行层以命令形式注册、可被任意调用方复用。通用提示工具utils.promptHydrationDialog3.11 将对话框提示逻辑统一封装在promptHydrationDialog中并作为ohif/extension-cornerstone的utils导出见 utils/index.ts 与 utils/promptHydrationDialog.ts。签名与参数export type HydrationCallback (params: any) Promiseboolean; export interface HydrationDialogProps { servicesManager: AppTypes.ServicesManager; viewportId: string; displaySet: AppTypes.DisplaySet; preHydrateCallbacks?: HydrationCallback[]; // 可选默认 [] hydrateCallback: HydrationCallback; // 用户确认后执行的回调 type: string; // SEG | SR | RTSTRUCT } function promptHydrationDialog({ servicesManager, viewportId, displaySet, preHydrateCallbacks [], hydrateCallback, type, }: HydrationDialogProps): Promiseboolean | HydrationSRResult各参数说明参数类型说明servicesManagerAppTypes.ServicesManagerOHIF 服务管理器内部用于取出uiViewportDialogService、customizationService以及_extensionManager上的appConfigviewportIdstring发起水合提示的视口 ID对话框将挂载到该视口上displaySetAppTypes.DisplaySet待水合的二次显示集SEG / RTSTRUCT / SR display setpreHydrateCallbacksHydrationCallback[]可选用户在对话框中确认后、执行hydrateCallback之前依次执行的钩子如保存当前呈现状态 presentation statehydrateCallbackHydrationCallback用户确认后真正执行水合的回调返回Promisebooleantypestring水合类型取自HydrationType枚举SEG、SR、RTSTRUCT返回值是一个 Promise非 SR 类型在用户确认并完成水合后解析为boolean成功为true用户取消则解析为falseSR 类型则返回结构化的HydrationSRResult详见下文SR 的特殊处理。类型常量与响应码promptHydrationDialog内部定义了两组关键常量export const HydrationType { SEG: SEG, SR: SR, RTSTRUCT: RTSTRUCT, } as const; const RESPONSE { NO_NEVER: -1, CANCEL: 0, CREATE_REPORT: 1, ADD_SERIES: 2, SET_STUDY_AND_SERIES: 3, NO_NOT_FOR_SERIES: 4, HYDRATE: 5, };其中RESPONSE.CANCEL用户点No或点击对话框外部与RESPONSE.HYDRATE用户点Yes或按 Enter是 RT/SEG 流程的两个关键分支只有HYDRATE才会继续执行preHydrateCallbacks与hydrateCallback。是否弹窗的判定逻辑这是 3.11 中最值得注意的行为变化之一。promptHydrationDialog通过appConfig决定是否真正弹出确认框const shouldPrompt type HydrationType.SR ? standardMode : !appConfig?.disableConfirmationPrompts;RTSTRUCT / SEG读取appConfig.disableConfirmationPrompts。为true时跳过对话框、直接视为用户确认RESPONSE.HYDRATE实现无感水合SR不看disableConfirmationPrompts而是检查appConfig.measurementTrackingMode standard即标准测量跟踪模式只有在 standard 模式下才弹窗询问。从源码注释promptHydrationDialog.ts可以看出这是刻意设计RT/SEG 关心是否关闭确认提示SR 关心是否处于标准测量跟踪模式。这一分支逻辑在 promptHydrationDialog.test.ts 中有大量针对性测试覆盖例如disableConfirmationPrompts为 true 时非 SR 类型应直接返回 HYDRATE 响应。对话框内容与交互的可定制性_askHydrate负责真正的对话框交互文案可定制消息内容通过customizationService.getCustomization(messageKey)获取按类型映射到不同的 customization keyswitch (type) { case HydrationType.RTSTRUCT: return viewportNotification.hydrateRTMessage; case HydrationType.SEG: return viewportNotification.hydrateSEGMessage; case HydrationType.SR: return viewportNotification.hydrateSRMessage; default: return viewportNotification.hydrateMessage; }这意味着应用可以通过 OHIF 的 customization 机制覆盖这些 key自定义弹窗文案而无需改扩展源码。交互方式对话框通过uiViewportDialogService.show(...)展示提供 Nosecondary样式值CANCEL与 Yesprimary样式值HYDRATE两个动作按钮点击外部区域等同于取消按 Enter 键等同于确认。SEG 与 RT 的执行差异用户确认后SEG 与 RTSTRUCT 均在window.setTimeout(..., 0)中异步执行hydrateCallback以让出主线程区别在于回调入参——SEG 收到{ segDisplaySet, viewportId }RTSTRUCT 收到{ rtDisplaySet, viewportId, servicesManager }。SR 的特殊处理SR 类型不走简单的 boolean 返回而是返回HydrationSRResultexport interface HydrationSRResult { userResponse: number; displaySetInstanceUID: string; srSeriesInstanceUID: string; viewportId: string; StudyInstanceUID?: string; SeriesInstanceUIDs?: string[]; }用户确认后hydrateCallback(displaySet)的返回值中若包含StudyInstanceUID/SeriesInstanceUIDs会一并并入结果供上层如测量跟踪上下文继续使用用户取消时同样返回带userResponse的结果对象而非false。迁移实操promptHydrateRT与promptHydrateSEG的改造原文档给出的迁移路径非常具体。以 RT 为例改造前后对照如下。promptHydrateRT删除旧对话框逻辑改为薄封装原文档展示的extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts变化- const RESPONSE { - NO_NEVER: -1, - CANCEL: 0, - HYDRATE_SEG: 5, - }; import { utils, Types } from ohif/extension-cornerstone; function promptHydrateRT({ servicesManager, rtDisplaySet, viewportId, preHydrateCallbacks, hydrateRTDisplaySet, -}: withAppTypes) { - const { uiViewportDialogService, customizationService } servicesManager.services; - // ... lots of old promise and dialog logic - return new Promise(async function (resolve, reject) { - // ... - }); -} - -function _askHydrate( - // ... -) { - // ... -} }: { servicesManager: AppTypes.ServicesManager; rtDisplaySet: AppTypes.DisplaySet; viewportId: string; preHydrateCallbacks?: Types.HydrationCallback[]; hydrateRTDisplaySet: Types.HydrationCallback; }) { return utils.promptHydrationDialog({ servicesManager, viewportId, displaySet: rtDisplaySet, preHydrateCallbacks, hydrateCallback: hydrateRTDisplaySet, type: RTSTRUCT, }); }对照当前仓库的实际实现extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts最终形态与 diff 中的新代码完全一致整个函数只剩 10 行左右的委托逻辑旧的RESPONSE常量与_askHydrate已彻底删除。promptHydrateSEG的改造同理见 extensions/cornerstone-dicom-seg/src/utils/promptHydrateSEG.ts只是type传SEG、入参名为segDisplaySet与hydrateCallback。调用方Viewport 内改由命令触发水合原文档展示的extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx变化useEffect(() { if (rtIsLoading) { return; } promptHydrateRT({ servicesManager, viewportId, rtDisplaySet, - preHydrateCallbacks: [storePresentationState], - hydrateRTDisplaySet, - }).then(isHydrated { - if (isHydrated) { - setIsHydrated(true); - } hydrateRTDisplaySet: async () { return commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: rtDisplaySet, viewportId, }); }, }); - }, [servicesManager, viewportId, rtDisplaySet, rtIsLoading]); }, [servicesManager, viewportId, rtDisplaySet, rtIsLoading, commandsManager]);对照当前实现OHIFCornerstoneRTViewport.tsx可以看到两个要点回调交给命令hydrateRTDisplaySet不再指向旧的自定义水合函数而是内联为commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: rtDisplaySet, viewportId })依赖数组补全useEffect的依赖数组加入了commandsManager当前实现还额外加入了activeViewportId且增加了非活动视口直接返回的守卫判断避免后台视口误触发水合提示。SEG 侧的实现对称OHIFCornerstoneSEGViewport.tsxpromptHydrateSEG的hydrateCallback同样调用hydrateSecondaryDisplaySet命令并显式返回true。SR 的对应改造SR 场景位于测量跟踪扩展中promptHydrateStructuredReport.ts它通过事件参数中的viewportId与displaySetInstanceUID定位显示集构造hydrateCallback调用hydrateSecondaryDisplaySet命令然后委托给utils.promptHydrationDialog并传type: SR。注意它额外做了enhancedSrDisplaySet的浅拷贝以补全displaySetInstanceUID字段说明 SR 调用方需要为对话框提供完整的显示集标识。执行核心hydrateSecondaryDisplaySet命令hydrateSecondaryDisplaySet注册于ohif/extension-cornerstone的 commandsModulecommandsModule.ts签名与核心逻辑如下hydrateSecondaryDisplaySet: async ({ displaySet, viewportId }) { if (!displaySet) { return; } const viewport cornerstoneViewportService.getCornerstoneViewport(viewportId); if (displaySet.isOverlayDisplaySet) { // 根据模态与视口类型推断分割表示类型 const segmentationType displaySet.Modality ! SEG ? SegmentationRepresentations.Contour : viewport isVolume3DViewportType(viewport) ? SegmentationRepresentations.Surface : SegmentationRepresentations.Labelmap; commandsManager.runCommand(updateStoredSegmentationPresentation, { displaySet, type: segmentationType, }); } // isHydrated 表示该显示集作为标准视图的一部分展示 // 该判定在这里完成不依赖视口是否已存在 displaySet.isHydrated true; const referencedDisplaySetInstanceUID displaySet.referencedDisplaySetInstanceUID; // ... };结合 commandsModule.ts 的后续分支该命令的核心职责可以归纳为空参守卫displaySet不存在时直接返回Overlay 显示集的表示类型推断对于isOverlayDisplaySet派生覆盖显示集根据Modality与视口类型决定分割表示——非 SEG如 RTSTRUCT用Contour轮廓SEG 在 3D 体积视口用Surface曲面否则用Labelmap标签图并调用updateStoredSegmentationPresentation更新存储的分割呈现标记isHydrated true这是命令对显示集状态的直接写入后续挂片协议与视口布局据此判定该显示集已是标准视图的一部分按模态分发SEG/RTSTRUCT先通过storePositionPresentation将引用显示集的位置呈现position/zoom/pan关联到目标视口再调用loadSegmentationDisplaySetsForViewport加载分割显示集并支持读取panelSegmentation.disableEditing定制项以在加载后锁定分割段SR调用hydrateStructuredReport命令并根据返回的SeriesInstanceUIDs解析被引用的显示集继续处理。此外命令内部还对水合后的多视口刷新做了处理见 utils/hydrationUtils.tsSEG 水合后除挂片协议匹配到的活动视口外还会按帧参考系frame of reference合并所有已展示同一体积的网格视口确保分割呈现同步应用到 MPR / 3D 瓦片这体现了 3.11 中水合 在它逻辑上应该出现的地方展示它的设计意图。迁移核对清单在 3.10 → 3.11 升级中完成 Hydration 相关代码迁移建议按以下清单核对删除各扩展内自有的RESPONSE常量与_askHydrate实现将promptHydrateSEG/promptHydrateRT收敛为对utils.promptHydrationDialog的薄封装将 Viewport 中的水合执行动作替换为hydrateSecondaryDisplaySet命令并确认useEffect依赖数组包含commandsManager以及必要的activeViewportId守卫确认 SR 场景使用type: SR走promptHydrationDialog的 SR 分支其返回值是HydrationSRResult而非boolean核对应用配置disableConfirmationPrompts决定 RT/SEG 是否弹窗measurementTrackingMode决定 SR 是否弹窗——若发现弹窗行为与 3.10 不同优先检查appConfig中的这两项如需定制文案通过 customization 覆盖viewportNotification.hydrateRTMessage/hydrateSEGMessage/hydrateSRMessage跑一遍测试promptHydrationDialog的判定与回调行为已由 promptHydrationDialog.test.ts 覆盖包括disableConfirmationPrompts、measurementTrackingMode、SEG 的延迟执行、SR 结果结构等分支升级后应确保这些用例通过。小结3.11 的 Hydration 体系本质上是把分散的、各写各的水合提示与执行逻辑收敛为promptHydrationDialog统一提示 hydrateSecondaryDisplaySet统一执行的两段式架构。对扩展开发者而言这意味着更少的样板代码、更统一的定制入口以及更可测试的行为边界——升级时只需按照本文的迁移清单替换旧函数与旧回调即可无缝接入新体系。【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表