OHIF Viewers 3.13 迁移指南:Mode 侧边栏面板列表成为标准定制项(Customization Service 运行时定制)
2026/9/18 22:40:10 网站建设 项目流程

OHIF Viewers 3.13 迁移指南:Mode 侧边栏面板列表成为标准定制项(Customization Service 运行时定制)

【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers

3.13 版本对 OHIF Viewers 的定制服务(customization service)做了一次重要收编:每个模式的左右侧边栏面板列表(leftPanels/rightPanels)不再只是布局里的字面量数组,而是被统一提升为标准定制项,任何模式都无需显式开启即可在运行时被?customization=数据文件或window.config覆盖。本文以迁移指南 mode-panels.md 为主体,结合仓库中的模式定义源码与已内置的 segmentation 定制模块,讲解新机制的解析顺序、定制写法与迁移注意事项,读完你就能在自己的部署中按模式替换、追加或全局调整侧边栏面板。

为什么面板列表会被"标准化"

在 3.13 之前,一个模式的侧边栏面板就是模式布局(layout)上两个普通的字面量数组:leftPanelsrightPanels。它们只有在模式定义代码里写死,部署者想改动必须修改模式源码。3.13 的变更核心在于:

  • 模式依然用同样的字面量数组声明面板(标准形式不变);
  • 但这些数组在模式进入(mode enter)时会被种子化(seed)到定制服务里,成为模式作用域(Mode scope)底层的标准定制项;
  • 之后应用的mode阶段定制块(app config / URL 中的定制模块)就可以用 immutability-helper 命令对它们做$set$push等组合操作。

也就是说,字面量数组形式没有被废弃,反而变成了"可定制的标准形式"。迁移指南原文将其概括为一句话:Modes declare their panels the standard way, as literal arrays in the layout,例如:

props: { leftPanels: ['@ohif/extension-default.panelModule.seriesList'], rightPanels: ['@ohif/extension-cornerstone.panelModule.panelMeasurement'], }

仓库中实际运行的例子就在 modes/basic/src/index.tsx 的basicLayout与 modes/longitudinal/src/index.ts 的longitudinalInstance里。basic 模式种子的左右列表为:

export const basicLayout = { id: ohif.layout, props: { leftPanels: [ohif.thumbnailList], leftPanelResizable: true, rightPanels: [cornerstone.segmentation, cornerstone.measurements], rightPanelClosed: true, rightPanelResizable: true, ... }, };

longitudinal 模式则在其上扩展,追加测量跟踪相关面板:

export const longitudinalInstance = { ...basicLayout, props: { ...basicLayout.props, leftPanels: [tracked.thumbnailList], rightPanels: [cornerstone.segmentation, tracked.measurements], ... }, };

这些布局 props 中的注释已经明确说明:the mode route seeds these into the standardleftPanels/rightPanelscustomizations at the bottom of the mode scope——它们正是本文主题的直接源码证据。

进入模式时的面板解析顺序(4 步)

迁移指南给出了模式进入时侧边栏的确定性解析流程。模式路由会自底向上(bottom-up)分层构建模式作用域,只有作用域构建完成后才真正解析侧边栏:

  1. 模式作用域被重置(reset)
  2. 布局的面板数组被种子化为标准的leftPanels/rightPanels定制项,构成模式作用域的最底层;
  3. app config / URL 的mode阶段块依次应用——先是通用的*块,再是按当前进入模式的 id / route name 命名的块;
  4. 侧边栏从最终的leftPanels/rightPanels值解析。全局作用域(global scope)的定制项照例通过作用域优先级(global > mode > default)胜出。

这 4 步顺序与同迁移指南中 mode-extensibility.md 描述的模式生命周期完全一致:模式实例在modeFactory中创建后,进入模式时模式作用域重置,然后依次叠上布局面板列表(即leftPanels/rightPanels)、modeCustomizations块、mode阶段*块与模式专属块,最后才由侧边栏、工具栏和onModeEnter消费这些值。

mode阶段块定制某个模式的侧边栏

因为模式自身的面板列表在mode阶段块应用时已经在定制服务里,所以一个?customization=模块(或window.config里的 customization 配置)只需在mode阶段块中定位标准键leftPanels/rightPanels,用 immutability-helper 命令与模式自身的列表组合即可。迁移指南给出的完整示例(JSONC,支持注释与尾逗号):

{ "mode": { // Replace the right sidebar in the longitudinal mode (route name `viewer`) "viewer": { "rightPanels": { "$set": [ "@ohif/extension-cornerstone.panelModule.panelSegmentationWithToolsLabelMap", "@ohif/extension-measurement-tracking.panelModule.trackedMeasurements" ] } }, // Append a panel in the segmentation mode "segmentation": { "rightPanels": { "$push": ["@ohif/extension-cornerstone.panelModule.panelMeasurement"] } }, // Or change every mode at once with the general block "*": { "leftPanels": { "$push": ["@ohif/extension-example.panelModule.myPanel"] } } } }

关键点解读

  • mode阶段块:定制模块可以按生命周期阶段划分载荷(requires/bootstrap/global/mode),详见 customization-url.md。mode阶段在每次模式进入时应用,作用于 Mode 作用域,*块先应用、按模式 id / routeName 命名的块后应用,因此模式专属块可以覆盖通用块的值。
  • 块键用 route name 而非面板 id:示例中 longitudinal 模式的 route name 是viewer(见 modes/longitudinal/src/index.ts 中的routeName: 'viewer'),所以定制块写作"viewer";segmentation 模式则写作"segmentation"
  • immutability-helper 语义$set整体替换模式种子的列表;$push在列表末尾追加;仓库内置示例中还可见$unshift(头部插入)等命令。这些命令与模式自身的列表天然组合——先有模式种子的底层值,再有命令式的修改层。
  • 面板 id 的格式:值为@ohif/extension-<name>.<moduleType>.<exportName>形式的完整引用串,与模式布局 props 中使用的引用格式一致。

该配置形态同样适用于window.config:app config 的customizationService接受相同的分阶段结构,例如仓库中的 config/customization.js 就展示了mode: { '*': ..., viewer: ... }的注释示例。

仓库内置的完整实战案例:segmentation 定制模块

迁移指南推荐直接参考平台内置的两个定制模块。它们在仓库中的路径为:

  • platform/app/public/customizations/segmentation/segmentationEditing.jsonc
  • platform/app/public/customizations/segmentation/segmentationAnnotationTools.jsonc

segmentationEditing.jsonc:替换右侧栏并启用分割编辑

该模块为 basic 与 longitudinal(viewer)模式组合分割编辑能力,全部修改都放在按 route name 命名的mode块中。其viewer块的核心内容:

{ "mode": { "viewer": { "toolbarButtons": { "$push": [{ "$reference": "cornerstone.segmentationToolbarButtons" }] }, "toolbarSections": { "$push": [{ "$reference": "cornerstone.segmentationToolbarSections" }] }, "toolGroupAdditions": { "default": { "$push": [{ "$reference": "cornerstone.segmentationTools" }] }, "mpr": { "$push": [{ "$reference": "cornerstone.segmentationTools" }] } }, "panelSegmentation.disableEditing": { "$set": false }, "rightPanels": { "$set": [ "@ohif/extension-cornerstone.panelModule.panelSegmentationWithToolsLabelMap", "@ohif/extension-cornerstone.panelModule.panelSegmentationWithToolsContour", "@ohif/extension-measurement-tracking.panelModule.trackedMeasurements" ] } } } }

其中"rightPanels": { "$set": [...] }与本文示例完全同构——整体替换模式种子化的右侧栏。文件注释还解释了它与modeCustomizations的协作:basic/longitudinal 模式会从自身modeCustomizations种子panelSegmentation.disableEditing: true,而此处mode阶段的值在其后应用(同在 Mode 作用域内、按应用顺序后者胜出),从而把编辑功能重新打开。这正是迁移指南 mode-extensibility.md 中"enableSegmentationEditmodeCustomizations取代"一节的运行时体现。

segmentationAnnotationTools.jsonc:追加测量面板

该模块在 segmentation 模式的右侧栏追加测量面板,是$push的典型用法:

{ "mode": { "segmentation": { "cornerstone.segmentationModeToolbarSections": { "primary": { "$unshift": ["MeasurementTools"] }, "MeasurementTools": { "$set": ["Length", "Bidirectional", "ArrowAnnotate", "..."] } }, "toolGroupAdditions": { "default": { "$push": [{ "$reference": "cornerstone.annotationTools" }] }, "mpr": { "$push": [{ "$reference": "cornerstone.annotationTools" }] } }, "rightPanels": { "$push": ["@ohif/extension-cornerstone.panelModule.panelMeasurement"] } } } }

两个模块的注释都强调了一个共同原则:组合是逐模式进行的,所有补丁都放在mode阶段、按目标模式的 route name 键控,因为每个模式进入时都会把自身的toolbarButtons/toolbarSections/toolGroupAdditions/rightPanels种子到 Mode 作用域上,这些块在其上$push/$set即可,完全不需要 app 级的global

迁移注意事项

迁移指南原文列出了两条明确的迁移要求,3.12 用户升级到 3.13 时务必核对:

  • 现有模式无需任何改动。字面量面板数组本就是标准形式,现在也自动成为可定制形式;没有自定义化需求的部署可以直接升级。
  • 早期 3.13 beta 的逐模式列表名已被移除。如果你曾针对basic.leftPanelslongitudinal.rightPanelssegmentation.rightPanelstmtv.leftPanels写过定制,需要改为:在mode阶段块中、以该模式的 route name 为键,使用标准键leftPanels/rightPanels(即上文示例的写法)。

此外,若你的定制同时依赖?customization=URL 加载能力,注意该能力在 3.13 中是默认关闭的,需要在 app config 顶层配置customizationUrlPrefixes白名单(例如{ default: './customizations/' })才能通过?customization=segmentation/segmentationEditing加载上述模块;未配置前缀的值会直接抛错并中止启动。相关细节见 customization-url.md。

小结

OHIF Viewers 3.13 将模式侧边栏面板列表收编为标准定制项,是"模式生命周期正则化"(见 mode-extensibility.md)思路的延续:不再有硬编码的特殊面板开关,一切由定制服务的作用域优先级(global > mode > default)加应用顺序统一裁决。对开发者而言,升级 3.13 后获得的能力是——无需修改模式源码,即可按模式(route name)、按全局、按命令式组合($set/$push/$unshift)自由编排左右侧边栏,内置的 segmentationEditing.jsonc 与 segmentationAnnotationTools.jsonc 就是可以直接复用的最佳范本。

【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询