fix(core): Address 3D reconstruction and Android compatibility issues and clean up 4D data mode (#4762)

This commit is contained in:
Alireza 2025-02-04 12:25:10 -05:00 committed by GitHub
parent 4d06a7d286
commit 149d6d049c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 529 additions and 529 deletions

View File

@ -2,7 +2,7 @@ version: 2.1
orbs: orbs:
codecov: codecov/codecov@1.0.5 codecov: codecov/codecov@1.0.5
cypress: cypress-io/cypress@3.3.1 cypress: cypress-io/cypress@3.4.2
defaults: &defaults defaults: &defaults
docker: docker:

310
bun.lock
View File

@ -32,7 +32,7 @@
}, },
"addOns/externals/devDependencies": { "addOns/externals/devDependencies": {
"name": "@externals/devDependencies", "name": "@externals/devDependencies",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
@ -120,19 +120,19 @@
}, },
"addOns/externals/dicom-microscopy-viewer": { "addOns/externals/dicom-microscopy-viewer": {
"name": "@externals/dicom-microscopy-viewer", "name": "@externals/dicom-microscopy-viewer",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"dicom-microscopy-viewer": "^0.46.1", "dicom-microscopy-viewer": "^0.46.1",
}, },
}, },
"extensions/cornerstone": { "extensions/cornerstone": {
"name": "@ohif/extension-cornerstone", "name": "@ohif/extension-cornerstone",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"@icr/polyseg-wasm": "^0.4.0", "@icr/polyseg-wasm": "^0.4.0",
"@itk-wasm/morphological-contour-interpolation": "1.1.0", "@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
@ -150,9 +150,9 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -164,19 +164,19 @@
}, },
"extensions/cornerstone-dicom-pmap": { "extensions/cornerstone-dicom-pmap": {
"name": "@ohif/extension-cornerstone-dicom-pmap", "name": "@ohif/extension-cornerstone-dicom-pmap",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -187,16 +187,16 @@
}, },
"extensions/cornerstone-dicom-rt": { "extensions/cornerstone-dicom-rt": {
"name": "@ohif/extension-cornerstone-dicom-rt", "name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -207,19 +207,19 @@
}, },
"extensions/cornerstone-dicom-seg": { "extensions/cornerstone-dicom-seg": {
"name": "@ohif/extension-cornerstone-dicom-seg", "name": "@ohif/extension-cornerstone-dicom-seg",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -230,19 +230,19 @@
}, },
"extensions/cornerstone-dicom-sr": { "extensions/cornerstone-dicom-sr": {
"name": "@ohif/extension-cornerstone-dicom-sr", "name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-measurement-tracking": "3.10.0-beta.82", "@ohif/extension-measurement-tracking": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -252,19 +252,19 @@
}, },
"extensions/cornerstone-dynamic-volume": { "extensions/cornerstone-dynamic-volume": {
"name": "@ohif/extension-cornerstone-dynamic-volume", "name": "@ohif/extension-cornerstone-dynamic-volume",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -274,14 +274,14 @@
}, },
"extensions/default": { "extensions/default": {
"name": "@ohif/extension-default", "name": "@ohif/extension-default",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/calculate-suv": "^1.1.0", "@cornerstonejs/calculate-suv": "^1.1.0",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicomweb-client": "^0.10.4", "dicomweb-client": "^0.10.4",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
@ -295,7 +295,7 @@
}, },
"extensions/dicom-microscopy": { "extensions/dicom-microscopy": {
"name": "@ohif/extension-dicom-microscopy", "name": "@ohif/extension-dicom-microscopy",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-charls": "^1.2.3",
@ -305,10 +305,10 @@
"mathjs": "^12.4.2", "mathjs": "^12.4.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -319,14 +319,14 @@
}, },
"extensions/dicom-pdf": { "extensions/dicom-pdf": {
"name": "@ohif/extension-dicom-pdf", "name": "@ohif/extension-dicom-pdf",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -336,14 +336,14 @@
}, },
"extensions/dicom-video": { "extensions/dicom-video": {
"name": "@ohif/extension-dicom-video", "name": "@ohif/extension-dicom-video",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -353,20 +353,20 @@
}, },
"extensions/measurement-tracking": { "extensions/measurement-tracking": {
"name": "@ohif/extension-measurement-tracking", "name": "@ohif/extension-measurement-tracking",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"@xstate/react": "^3.2.2", "@xstate/react": "^3.2.2",
"xstate": "^4.10.0", "xstate": "^4.10.0",
}, },
"peerDependencies": { "peerDependencies": {
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"dcmjs": "*", "dcmjs": "*",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
@ -379,14 +379,14 @@
}, },
"extensions/test-extension": { "extensions/test-extension": {
"name": "@ohif/extension-test", "name": "@ohif/extension-test",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "0.38.0", "dcmjs": "0.38.0",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -396,14 +396,14 @@
}, },
"extensions/tmtv": { "extensions/tmtv": {
"name": "@ohif/extension-tmtv", "name": "@ohif/extension-tmtv",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -413,7 +413,7 @@
}, },
"modes/basic-dev-mode": { "modes/basic-dev-mode": {
"name": "@ohif/mode-basic-dev-mode", "name": "@ohif/mode-basic-dev-mode",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -423,17 +423,17 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
}, },
}, },
"modes/basic-test-mode": { "modes/basic-test-mode": {
"name": "@ohif/mode-test", "name": "@ohif/mode-test",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -443,19 +443,19 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
"@ohif/extension-measurement-tracking": "3.10.0-beta.82", "@ohif/extension-measurement-tracking": "3.10.0-beta.91",
"@ohif/extension-test": "3.10.0-beta.82", "@ohif/extension-test": "3.10.0-beta.91",
}, },
}, },
"modes/longitudinal": { "modes/longitudinal": {
"name": "@ohif/mode-longitudinal", "name": "@ohif/mode-longitudinal",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -465,32 +465,32 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
"@ohif/extension-measurement-tracking": "3.10.0-beta.82", "@ohif/extension-measurement-tracking": "3.10.0-beta.91",
}, },
}, },
"modes/microscopy": { "modes/microscopy": {
"name": "@ohif/mode-microscopy", "name": "@ohif/mode-microscopy",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-dicom-microscopy": "3.10.0-beta.82", "@ohif/extension-dicom-microscopy": "3.10.0-beta.91",
}, },
}, },
"modes/preclinical-4d": { "modes/preclinical-4d": {
"name": "@ohif/mode-preclinical-4d", "name": "@ohif/mode-preclinical-4d",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
}, },
@ -499,17 +499,17 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.82", "@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-tmtv": "3.10.0-beta.82", "@ohif/extension-tmtv": "3.10.0-beta.91",
}, },
}, },
"modes/segmentation": { "modes/segmentation": {
"name": "@ohif/mode-segmentation", "name": "@ohif/mode-segmentation",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -541,19 +541,19 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
}, },
}, },
"modes/tmtv": { "modes/tmtv": {
"name": "@ohif/mode-tmtv", "name": "@ohif/mode-tmtv",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -563,43 +563,43 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
"@ohif/extension-measurement-tracking": "3.10.0-beta.82", "@ohif/extension-measurement-tracking": "3.10.0-beta.91",
}, },
}, },
"platform/app": { "platform/app": {
"name": "@ohif/app", "name": "@ohif/app",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-charls": "^1.2.3",
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@emotion/serialize": "^1.1.3", "@emotion/serialize": "^1.1.3",
"@ohif/core": "3.10.0-beta.82", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.82", "@ohif/extension-cornerstone": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.82", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.82", "@ohif/extension-default": "3.10.0-beta.91",
"@ohif/extension-dicom-microscopy": "3.10.0-beta.82", "@ohif/extension-dicom-microscopy": "3.10.0-beta.91",
"@ohif/extension-dicom-pdf": "3.10.0-beta.82", "@ohif/extension-dicom-pdf": "3.10.0-beta.91",
"@ohif/extension-dicom-video": "3.10.0-beta.82", "@ohif/extension-dicom-video": "3.10.0-beta.91",
"@ohif/extension-test": "3.10.0-beta.82", "@ohif/extension-test": "3.10.0-beta.91",
"@ohif/i18n": "3.10.0-beta.82", "@ohif/i18n": "3.10.0-beta.91",
"@ohif/mode-basic-dev-mode": "3.10.0-beta.82", "@ohif/mode-basic-dev-mode": "3.10.0-beta.91",
"@ohif/mode-longitudinal": "3.10.0-beta.82", "@ohif/mode-longitudinal": "3.10.0-beta.91",
"@ohif/mode-microscopy": "3.10.0-beta.82", "@ohif/mode-microscopy": "3.10.0-beta.91",
"@ohif/mode-test": "3.10.0-beta.82", "@ohif/mode-test": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"@ohif/ui-next": "3.10.0-beta.82", "@ohif/ui-next": "3.10.0-beta.91",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"classnames": "^2.3.2", "classnames": "^2.3.2",
@ -641,7 +641,7 @@
}, },
"platform/cli": { "platform/cli": {
"name": "@ohif/cli", "name": "@ohif/cli",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"bin": { "bin": {
"ohif-cli": "src/index.js" "ohif-cli": "src/index.js"
}, },
@ -665,7 +665,7 @@
}, },
"platform/core": { "platform/core": {
"name": "@ohif/core", "name": "@ohif/core",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"dcmjs": "*", "dcmjs": "*",
@ -691,15 +691,15 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@ohif/ui": "3.10.0-beta.82", "@ohif/ui": "3.10.0-beta.91",
"cornerstone-math": "0.1.9", "cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
}, },
}, },
"platform/i18n": { "platform/i18n": {
"name": "@ohif/i18n", "name": "@ohif/i18n",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next-locize-backend": "^2.0.0", "i18next-locize-backend": "^2.0.0",
@ -724,7 +724,7 @@
}, },
"platform/ui": { "platform/ui": {
"name": "@ohif/ui", "name": "@ohif/ui",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@testing-library/react": "^13.1.0", "@testing-library/react": "^13.1.0",
"browser-detect": "^0.2.28", "browser-detect": "^0.2.28",
@ -782,7 +782,7 @@
}, },
"platform/ui-next": { "platform/ui-next": {
"name": "@ohif/ui-next", "name": "@ohif/ui-next",
"version": "3.10.0-beta.82", "version": "3.10.0-beta.91",
"dependencies": { "dependencies": {
"@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1",
@ -1091,7 +1091,7 @@
"@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@2.18.2", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^2.18.2", "@cornerstonejs/tools": "^2.18.2" } }, "sha512-Tm2izseStXcPQwrXmD6T3X8ybnFwjPyGltVTYvqwwlzLw4quuPw1B60scvY13rKrg3Pl04smYNqfw37nzIFjQQ=="], "@cornerstonejs/adapters": ["@cornerstonejs/adapters@2.19.3", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^2.19.3", "@cornerstonejs/tools": "^2.19.3" } }, "sha512-QuugcUCelTW9bxhO1yewuuf6UHbIufiWMU+plNp40RwR92hgWi1SB9K/gFhtSRxVBqnkbG3Sh6mZRSuS3KcP1A=="],
"@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="], "@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="],
@ -1103,11 +1103,11 @@
"@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="], "@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
"@cornerstonejs/core": ["@cornerstonejs/core@2.18.2", "", { "dependencies": { "@kitware/vtk.js": "32.9.0", "comlink": "^4.4.1", "gl-matrix": "^3.4.3" } }, "sha512-nlkWBL56I9gYFy/77loFyPjFGe7R72kQFRPtcIcGZ89Jnz3nwZSjGma7taJJjiSfb2YnUUhmT4HvzsqQlClPdg=="], "@cornerstonejs/core": ["@cornerstonejs/core@2.19.3", "", { "dependencies": { "@kitware/vtk.js": "32.9.0", "comlink": "^4.4.1", "gl-matrix": "^3.4.3" } }, "sha512-yqPFpfzKCNj9U94q1do8oE3adg7+/t+bc4uBHrNPCvbUyOqaWZzentw5+79cj5hhHif2OG0jVNRSPr+kbBBk2Q=="],
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@2.18.2", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^2.18.2", "dicom-parser": "^1.8.9" } }, "sha512-m9GFwsrChJdWGYG8OZGGeSft89cUaPLlkw2pd5kDLxJz0874nJQgTp27L7o/mjRXqEijQhiPNtWdSvwUZv60pg=="], "@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@2.19.3", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^2.19.3", "dicom-parser": "^1.8.9" } }, "sha512-/VTmaDabIqF8lBzPq0yK3yF6TIb3vTEoMeyvXTQWpPG1wjiTRAaYql5uQjCgE1p/xCXVA3Iq+h2rk90HWFu6nA=="],
"@cornerstonejs/tools": ["@cornerstonejs/tools@2.18.2", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^2.18.2", "@kitware/vtk.js": "32.9.0", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-Xxfl3JWB86tN/GAawFwKApfglu+3rFZyRSKyvnpUl8aAPomjhvbt93l2H8VDliw+JuCEgrUwCu0LQl0wumpR2Q=="], "@cornerstonejs/tools": ["@cornerstonejs/tools@2.19.3", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^2.19.3", "@kitware/vtk.js": "32.9.0", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-bJFhE2b1B2k8enZT9vZqspLXmSHqCLAOFwib5FWi4/9AtNydVaDBIafAYq/gCXTcF8YcbsUhBhWQL1LU7ejkWg=="],
"@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@1.1.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.2" } }, "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA=="], "@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@1.1.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.2" } }, "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA=="],

View File

@ -46,8 +46,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3" "react-color": "^2.19.3"
} }

View File

@ -46,8 +46,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3" "react-color": "^2.19.3"
} }

View File

@ -46,9 +46,9 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"classnames": "^2.3.2" "classnames": "^2.3.2"
} }
} }

View File

@ -42,8 +42,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"classnames": "^2.3.2" "classnames": "^2.3.2"
} }
} }

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Button, PanelSection, ButtonGroup, IconButton, InputNumber } from '@ohif/ui'; import { Button, PanelSection, ButtonGroup, IconButton, InputNumber } from '@ohif/ui';
import { DoubleSlider, Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next'; import { Icons, Tooltip, TooltipTrigger, TooltipContent, Numeric } from '@ohif/ui-next';
import { Enums } from '@cornerstonejs/core'; import { Enums } from '@cornerstonejs/core';
const controlClassNames = { const controlClassNames = {
@ -20,7 +20,10 @@ const Header = ({ title, tooltip }) => (
/> />
</span> </span>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent sideOffset={4} className="max-w-xs p-2 bg-primary-dark text-white"> <TooltipContent
sideOffset={4}
className="bg-primary-dark max-w-xs p-2 text-white"
>
<div>{tooltip}</div> <div>{tooltip}</div>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
@ -37,23 +40,16 @@ const DynamicVolumeControls = ({
minFps, minFps,
maxFps, maxFps,
// Frames // Frames
currentFrameIndex, currentDimensionGroupNumber,
onFrameChange, onDimensionGroupChange,
framesLength, numDimensionGroups,
onGenerate, onGenerate,
onDoubleRangeChange, onDoubleRangeChange,
rangeValues,
onDynamicClick, onDynamicClick,
}) => { }) => {
const [computedView, setComputedView] = useState(false); const [computedView, setComputedView] = useState(false);
const [computeViewMode, setComputeViewMode] = useState(Enums.DynamicOperatorType.SUM); const [computeViewMode, setComputeViewMode] = useState(Enums.DynamicOperatorType.SUM);
const [sliderRangeValues, setSliderRangeValues] = useState([0, framesLength - 1]);
const handleSliderChange = newValues => {
onDoubleRangeChange(newValues);
setSliderRangeValues(newValues);
};
const formatLabel = value => Math.round(value);
return ( return (
<div className="flex select-none flex-col"> <div className="flex select-none flex-col">
@ -89,7 +85,7 @@ const DynamicVolumeControls = ({
</ButtonGroup> </ButtonGroup>
</div> </div>
<div> <div>
<FrameControls <DimensionGroupControls
onPlayPauseChange={onPlayPauseChange} onPlayPauseChange={onPlayPauseChange}
isPlaying={isPlaying} isPlaying={isPlaying}
computedView={computedView} computedView={computedView}
@ -99,9 +95,9 @@ const DynamicVolumeControls = ({
minFps={minFps} minFps={minFps}
maxFps={maxFps} maxFps={maxFps}
// //
framesLength={framesLength} numDimensionGroups={numDimensionGroups}
onFrameChange={onFrameChange} onDimensionGroupChange={onDimensionGroupChange}
currentFrameIndex={currentFrameIndex} currentDimensionGroupNumber={currentDimensionGroupNumber}
/> />
</div> </div>
<div className={`mt-6 flex flex-col ${computedView ? '' : 'ohif-disabled'}`}> <div className={`mt-6 flex flex-col ${computedView ? '' : 'ohif-disabled'}`}>
@ -111,9 +107,10 @@ const DynamicVolumeControls = ({
<div> <div>
Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to be Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to be
applied to the data set. applied to the data set.
<br /> Range Slider: Choose the numeric range within which the operation will be <br /> Range Slider: Choose the numeric range of dimension groups within which the
performed. operation will be performed.
<br />Generate Button: Execute the chosen operation on the specified range of data. <br />
Generate Button: Execute the chosen operation on the specified range of data.
</div> </div>
} }
/> />
@ -141,15 +138,15 @@ const DynamicVolumeControls = ({
</button> </button>
</ButtonGroup> </ButtonGroup>
<div className="mt-2 w-full"> <div className="mt-2 w-full">
<DoubleSlider <Numeric.Container
min={0} mode="doubleRange"
max={framesLength - 1} min={1}
step={1} max={numDimensionGroups}
defaultValue={sliderRangeValues} values={rangeValues}
onValueChange={handleSliderChange} onChange={onDoubleRangeChange}
formatLabel={formatLabel} >
className="w-full" <Numeric.DoubleRange showNumberInputs />
/> </Numeric.Container>
</div> </div>
<Button <Button
className="mt-2 !h-[26px] !w-[115px] self-start !p-0" className="mt-2 !h-[26px] !w-[115px] self-start !p-0"
@ -167,16 +164,16 @@ const DynamicVolumeControls = ({
export default DynamicVolumeControls; export default DynamicVolumeControls;
function FrameControls({ function DimensionGroupControls({
isPlaying, isPlaying,
onPlayPauseChange, onPlayPauseChange,
fps, fps,
minFps, minFps,
maxFps, maxFps,
onFpsChange, onFpsChange,
framesLength, numDimensionGroups,
onFrameChange, onDimensionGroupChange,
currentFrameIndex, currentDimensionGroupNumber,
computedView, computedView,
}) { }) {
const getPlayPauseIconName = () => (isPlaying ? 'icon-pause' : 'icon-play'); const getPlayPauseIconName = () => (isPlaying ? 'icon-pause' : 'icon-play');
@ -187,14 +184,16 @@ function FrameControls({
title="4D Controls" title="4D Controls"
tooltip={ tooltip={
<div> <div>
Play/Pause Button: Begin or pause the animation of the 4D visualization. <br /> Frame Play/Pause Button: Begin or pause the animation of the 4D visualization. <br />
Selector: Navigate through individual frames of the 4D data. <br /> FPS (Frames Per Dimension Group Selector: Navigate through individual dimension groups of the 4D data.{' '}
Second) Selector: Adjust the playback speed of the animation. <br />
FPS (Frames Per Second) Selector: Adjust the playback speed of the animation.
</div> </div>
} }
/> />
<div className="mt-3 flex justify-between"> <div className="mt-3 flex justify-between">
<IconButton <IconButton
id="play-pause-button"
className="bg-customblue-30 h-[26px] w-[58px] rounded-[4px]" className="bg-customblue-30 h-[26px] w-[58px] rounded-[4px]"
onClick={() => onPlayPauseChange(!isPlaying)} onClick={() => onPlayPauseChange(!isPlaying)}
> >
@ -204,11 +203,11 @@ function FrameControls({
/> />
</IconButton> </IconButton>
<InputNumber <InputNumber
value={currentFrameIndex} value={currentDimensionGroupNumber}
onChange={onFrameChange} onChange={onDimensionGroupChange}
minValue={0} minValue={1}
maxValue={framesLength - 1} maxValue={numDimensionGroups}
label="Frame" label="Group"
{...controlClassNames} {...controlClassNames}
/> />
<InputNumber <InputNumber

View File

@ -15,13 +15,12 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
const [{ activeViewportId }] = useViewportGrid(); const [{ activeViewportId }] = useViewportGrid();
// //
const [timePointsRange, setTimePointsRange] = useState([0, 0]); const [dimensionGroupRange, setDimensionGroupRange] = useState([1, 1]);
const [timePointsRangeToUseForGenerate, setTimePointsRangeToUseForGenerate] = useState([0, 0]);
const [computedDisplaySet, setComputedDisplaySet] = useState(null); const [computedDisplaySet, setComputedDisplaySet] = useState(null);
const [dynamicVolume, setDynamicVolume] = useState(null); const [dynamicVolume, setDynamicVolume] = useState(null);
const [frameRate, setFrameRate] = useState(20); const [frameRate, setFrameRate] = useState(20);
const [isPlaying, setIsPlaying] = useState(isCineEnabled); const [isPlaying, setIsPlaying] = useState(isCineEnabled);
const [timePointRendered, setTimePointRendered] = useState(null); const [dimensionGroupNumberRendered, setDimensionGroupNumberRendered] = useState(null);
const [displayingComputed, setDisplayingComputed] = useState(false); const [displayingComputed, setDisplayingComputed] = useState(false);
// //
@ -38,9 +37,8 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
if (volumeData.volume?.isDynamicVolume()) { if (volumeData.volume?.isDynamicVolume()) {
setDynamicVolume(volumeData.volume); setDynamicVolume(volumeData.volume);
uuidDynamicVolume.current = volumeData.displaySetInstanceUID; uuidDynamicVolume.current = volumeData.displaySetInstanceUID;
const newRange = [1, volumeData.volume.numTimePoints]; const newRange = [1, volumeData.volume.numDimensionGroups];
setTimePointsRange(newRange); setDimensionGroupRange(newRange);
setTimePointsRangeToUseForGenerate(newRange);
} }
}); });
}; };
@ -65,10 +63,10 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
}, [cornerstoneViewportService, cineService, servicesManager.services.cineService]); }, [cornerstoneViewportService, cineService, servicesManager.services.cineService]);
useEffect(() => { useEffect(() => {
const evt = Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED; const evt = Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED;
const callback = evt => { const callback = evt => {
setTimePointRendered(evt.detail.timePointIndex); setDimensionGroupNumberRendered(evt.detail.dimensionGroupNumber);
}; };
eventTarget.addEventListener(evt, callback); eventTarget.addEventListener(evt, callback);
@ -76,7 +74,7 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
return () => { return () => {
eventTarget.removeEventListener(evt, callback); eventTarget.removeEventListener(evt, callback);
}; };
}, [cornerstoneViewportService]); }, []);
useEffect(() => { useEffect(() => {
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId); const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId);
@ -102,9 +100,7 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
setDynamicVolume(dynamicVolume); setDynamicVolume(dynamicVolume);
uuidDynamicVolume.current = dynamicVolumeDisplaySet.displaySetInstanceUID; uuidDynamicVolume.current = dynamicVolumeDisplaySet.displaySetInstanceUID;
const newRange = [1, dynamicVolume.numTimePoints]; setDimensionGroupRange([1, dynamicVolume.numDimensionGroups]);
setTimePointsRange(newRange);
setTimePointsRangeToUseForGenerate(newRange);
}, [ }, [
activeViewportId, activeViewportId,
viewportGridService, viewportGridService,
@ -141,11 +137,12 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
volumeId: computedVolumeId, volumeId: computedVolumeId,
}); });
} }
const [start, end] = timePointsRangeToUseForGenerate; const [start, end] = dimensionGroupRange;
const frameNumbers = Array.from({ length: end - start + 1 }, (_, i) => i + start - 1); // from start to end, with steps of 1
const frameNumbers = Array.from({ length: end - start + 1 }, (_, i) => start + i);
const options = { const options = {
frameNumbers: operationName === 'SUBTRACT' ? [start, end - 1] : frameNumbers, dimensionGroupNumbers: operationName === 'SUBTRACT' ? [start, end] : frameNumbers,
targetVolume: computedVolume, targetVolume: computedVolume,
}; };
@ -207,17 +204,6 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
handlePlay(); handlePlay();
}; };
function handleSliderChange(newValues) {
if (
newValues[0] === timePointsRangeToUseForGenerate[0] &&
newValues[1] === timePointsRangeToUseForGenerate[1]
) {
return;
}
setTimePointsRangeToUseForGenerate(newValues);
}
return ( return (
<DynamicVolumeControls <DynamicVolumeControls
fps={frameRate} fps={frameRate}
@ -225,16 +211,16 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
onPlayPauseChange={onPlayPauseChange} onPlayPauseChange={onPlayPauseChange}
minFps={1} minFps={1}
maxFps={50} maxFps={50}
currentFrameIndex={timePointRendered}
onFpsChange={handleSetFrameRate} onFpsChange={handleSetFrameRate}
framesLength={timePointsRange[1]} currentDimensionGroupNumber={dimensionGroupNumberRendered}
onFrameChange={timePointIndex => { numDimensionGroups={dynamicVolume?.numDimensionGroups || 1}
dynamicVolume.timePointIndex = timePointIndex; onDimensionGroupChange={dimensionGroupNumber => {
dynamicVolume.dimensionGroupNumber = dimensionGroupNumber;
}} }}
onGenerate={onGenerateImage} onGenerate={onGenerateImage}
onDynamicClick={displayingComputed ? () => renderDynamicImage(computedDisplaySet) : null} onDynamicClick={displayingComputed ? () => renderDynamicImage(computedDisplaySet) : null}
onDoubleRangeChange={handleSliderChange} onDoubleRangeChange={setDimensionGroupRange}
initialRangeValues={timePointsRangeToUseForGenerate} rangeValues={dimensionGroupRange}
/> />
); );
} }

View File

@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@ohif/core": "3.10.0-beta.91", "@ohif/core": "3.10.0-beta.91",
"@ohif/ui": "3.10.0-beta.91", "@ohif/ui": "3.10.0-beta.91",
"dcmjs": "*", "dcmjs": "*",
@ -54,9 +54,9 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.17.2", "@cornerstonejs/adapters": "^2.19.3",
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"@icr/polyseg-wasm": "^0.4.0", "@icr/polyseg-wasm": "^0.4.0",
"@itk-wasm/morphological-contour-interpolation": "1.1.0", "@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.1.1", "@kitware/vtk.js": "32.1.1",

View File

@ -53,13 +53,13 @@ function WrappedCinePlayer({
// check if the displaySet is dynamic and set the dynamic info // check if the displaySet is dynamic and set the dynamic info
if (displaySet.isDynamicVolume) { if (displaySet.isDynamicVolume) {
const { dynamicVolumeInfo } = displaySet; const { dynamicVolumeInfo } = displaySet;
const numTimePoints = dynamicVolumeInfo.timePoints.length; const numDimensionGroups = dynamicVolumeInfo.timePoints.length;
const label = dynamicVolumeInfo.splittingTag; const label = dynamicVolumeInfo.splittingTag;
const timePointIndex = dynamicVolumeInfo.timePointIndex || 0; const dimensionGroupNumber = dynamicVolumeInfo.dimensionGroupNumber || 1;
setDynamicInfo({ setDynamicInfo({
volumeId: displaySet.displaySetInstanceUID, volumeId: displaySet.displaySetInstanceUID,
timePointIndex, dimensionGroupNumber,
numTimePoints, numDimensionGroups,
label, label,
}); });
} else { } else {
@ -176,20 +176,20 @@ function RenderCinePlayer({
return; return;
} }
const handleTimePointIndexChange = evt => { const handleDimensionGroupChange = evt => {
const { volumeId, timePointIndex, numTimePoints, splittingTag } = evt.detail; const { volumeId, dimensionGroupNumber, numDimensionGroups, splittingTag } = evt.detail;
setDynamicInfo({ volumeId, timePointIndex, numTimePoints, label: splittingTag }); setDynamicInfo({ volumeId, dimensionGroupNumber, numDimensionGroups, label: splittingTag });
}; };
eventTarget.addEventListener( eventTarget.addEventListener(
Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED, Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED,
handleTimePointIndexChange handleDimensionGroupChange
); );
return () => { return () => {
eventTarget.removeEventListener( eventTarget.removeEventListener(
Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED, Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED,
handleTimePointIndexChange handleDimensionGroupChange
); );
}; };
}, [dynamicInfo]); }, [dynamicInfo]);
@ -199,17 +199,17 @@ function RenderCinePlayer({
return; return;
} }
const { volumeId, timePointIndex, numTimePoints, splittingTag } = dynamicInfo || {}; const { volumeId, dimensionGroupNumber, numDimensionGroups, splittingTag } = dynamicInfo || {};
const volume = cache.getVolume(volumeId, true); const volume = cache.getVolume(volumeId, true);
volume.timePointIndex = timePointIndex; volume.dimensionGroupNumber = dimensionGroupNumber;
setDynamicInfo({ volumeId, timePointIndex, numTimePoints, label: splittingTag }); setDynamicInfo({ volumeId, dimensionGroupNumber, numDimensionGroups, label: splittingTag });
}, []); }, []);
const updateDynamicInfo = useCallback(props => { const updateDynamicInfo = useCallback(props => {
const { volumeId, timePointIndex } = props; const { volumeId, dimensionGroupNumber } = props;
const volume = cache.getVolume(volumeId, true); const volume = cache.getVolume(volumeId, true);
volume.timePointIndex = timePointIndex; volume.dimensionGroupNumber = dimensionGroupNumber;
}, []); }, []);
return ( return (

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const fourUp = { export const fourUp = {
id: 'fourUp', id: 'fourUp',
locked: true, locked: true,
@ -46,17 +48,7 @@ export const fourUp = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -72,6 +64,7 @@ export const fourUp = {
customViewportProps: { customViewportProps: {
hideOverlays: true, hideOverlays: true,
}, },
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
}, },
displaySets: [ displaySets: [
{ {
@ -94,17 +87,7 @@ export const fourUp = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -120,17 +103,7 @@ export const fourUp = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const main3D = { export const main3D = {
id: 'main3D', id: 'main3D',
locked: true, locked: true,
@ -94,17 +96,7 @@ export const main3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -120,17 +112,7 @@ export const main3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -146,17 +128,7 @@ export const main3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {

View File

@ -1,6 +1,6 @@
import { Types } from '@ohif/core'; import { Types } from '@ohif/core';
const VOI_SYNC_GROUP = { export const VOI_SYNC_GROUP = {
type: 'voi', type: 'voi',
id: 'mpr', id: 'mpr',
source: true, source: true,
@ -10,7 +10,7 @@ const VOI_SYNC_GROUP = {
}, },
}; };
const HYDRATE_SEG_SYNC_GROUP = { export const HYDRATE_SEG_SYNC_GROUP = {
type: 'hydrateseg', type: 'hydrateseg',
id: 'sameFORId', id: 'sameFORId',
source: true, source: true,

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const mprAnd3DVolumeViewport = { export const mprAnd3DVolumeViewport = {
id: 'mprAnd3DVolumeViewport', id: 'mprAnd3DVolumeViewport',
locked: true, locked: true,
@ -53,17 +55,7 @@ export const mprAnd3DVolumeViewport = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -79,6 +71,7 @@ export const mprAnd3DVolumeViewport = {
customViewportProps: { customViewportProps: {
hideOverlays: true, hideOverlays: true,
}, },
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
}, },
displaySets: [ displaySets: [
{ {
@ -101,17 +94,7 @@ export const mprAnd3DVolumeViewport = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -127,17 +110,7 @@ export const mprAnd3DVolumeViewport = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const only3D = { export const only3D = {
id: 'only3D', id: 'only3D',
locked: true, locked: true,
@ -45,6 +47,7 @@ export const only3D = {
orientation: 'coronal', orientation: 'coronal',
customViewportProps: { customViewportProps: {
hideOverlays: true, hideOverlays: true,
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
}, },
}, },
displaySets: [ displaySets: [

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const primary3D = { export const primary3D = {
id: 'primary3D', id: 'primary3D',
locked: true, locked: true,
@ -94,17 +96,7 @@ export const primary3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -120,17 +112,7 @@ export const primary3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -146,17 +128,7 @@ export const primary3D = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {

View File

@ -1,3 +1,5 @@
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
export const primaryAxial = { export const primaryAxial = {
id: 'primaryAxial', id: 'primaryAxial',
locked: true, locked: true,
@ -66,17 +68,7 @@ export const primaryAxial = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -92,17 +84,7 @@ export const primaryAxial = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {
@ -118,17 +100,7 @@ export const primaryAxial = {
initialImageOptions: { initialImageOptions: {
preset: 'middle', preset: 'middle',
}, },
syncGroups: [ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
{
type: 'voi',
id: 'mpr',
source: true,
target: true,
options: {
syncColormap: true,
},
},
],
}, },
displaySets: [ displaySets: [
{ {

View File

@ -1,22 +1,18 @@
import { useEffect, useState, memo } from 'react'; import { useEffect, useState, memo, useCallback } from 'react';
const ActiveViewportBehavior = memo( const ActiveViewportBehavior = memo(
({ servicesManager, viewportId }: withAppTypes<{ viewportId: string }>) => { ({ servicesManager, viewportId }: withAppTypes<{ viewportId: string }>) => {
const { displaySetService, cineService, viewportGridService, customizationService } = const {
servicesManager.services; displaySetService,
cineService,
viewportGridService,
customizationService,
cornerstoneViewportService,
} = servicesManager.services;
const [activeViewportId, setActiveViewportId] = useState(viewportId); const [activeViewportId, setActiveViewportId] = useState(viewportId);
useEffect(() => { const handleCineEnable = useCallback(() => {
const subscription = viewportGridService.subscribe(
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
({ viewportId }) => setActiveViewportId(viewportId)
);
return () => subscription.unsubscribe();
}, [viewportId, viewportGridService]);
useEffect(() => {
if (cineService.isViewportCineClosed(activeViewportId)) { if (cineService.isViewportCineClosed(activeViewportId)) {
return; return;
} }
@ -54,6 +50,32 @@ const ActiveViewportBehavior = memo(
customizationService, customizationService,
]); ]);
useEffect(() => {
const subscription = viewportGridService.subscribe(
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
({ viewportId }) => setActiveViewportId(viewportId)
);
return () => subscription.unsubscribe();
}, [viewportId, viewportGridService]);
useEffect(() => {
const subscription = cornerstoneViewportService.subscribe(
cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
() => {
const activeViewportId = viewportGridService.getActiveViewportId();
setActiveViewportId(activeViewportId);
handleCineEnable();
}
);
return () => subscription.unsubscribe();
}, [viewportId, cornerstoneViewportService, viewportGridService, handleCineEnable]);
useEffect(() => {
handleCineEnable();
}, [handleCineEnable]);
return null; return null;
}, },
arePropsEqual arePropsEqual

View File

@ -0,0 +1,5 @@
import { MeasurementItem } from '@ohif/ui';
export default {
'microscopyPanel.measurementItem': MeasurementItem,
};

View File

@ -0,0 +1,12 @@
import panelMeasurementItem from './customizations/panelMeasurementItem';
export default function getCustomizationModule() {
return [
{
name: 'default',
value: {
...panelMeasurementItem,
},
},
];
}

View File

@ -2,6 +2,7 @@ import { id } from './id';
import React, { Suspense, useMemo } from 'react'; import React, { Suspense, useMemo } from 'react';
import getPanelModule from './getPanelModule'; import getPanelModule from './getPanelModule';
import getCommandsModule from './getCommandsModule'; import getCommandsModule from './getCommandsModule';
import getCustomizationModule from './getCustomizationModule';
import { Types } from '@ohif/core'; import { Types } from '@ohif/core';
import { useViewportGrid } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next';
@ -158,6 +159,8 @@ const extension: Types.Extensions.Extension = {
getPanelModule, getPanelModule,
getCommandsModule, getCommandsModule,
getCustomizationModule,
}; };
export default extension; export default extension;

View File

@ -32,8 +32,8 @@
"start": "yarn run dev" "start": "yarn run dev"
}, },
"peerDependencies": { "peerDependencies": {
"@cornerstonejs/core": "^2.17.2", "@cornerstonejs/core": "^2.19.3",
"@cornerstonejs/tools": "^2.17.2", "@cornerstonejs/tools": "^2.19.3",
"@ohif/core": "3.10.0-beta.91", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.91",
"@ohif/extension-default": "3.10.0-beta.91", "@ohif/extension-default": "3.10.0-beta.91",

View File

@ -54,7 +54,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@emotion/serialize": "^1.1.3", "@emotion/serialize": "^1.1.3",
"@ohif/core": "3.10.0-beta.91", "@ohif/core": "3.10.0-beta.91",
"@ohif/extension-cornerstone": "3.10.0-beta.91", "@ohif/extension-cornerstone": "3.10.0-beta.91",

View File

@ -37,7 +37,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.17.2", "@cornerstonejs/dicom-image-loader": "^2.19.3",
"@ohif/ui": "3.10.0-beta.91", "@ohif/ui": "3.10.0-beta.91",
"cornerstone-math": "0.1.9", "cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21" "dicom-parser": "^1.8.21"

View File

@ -285,14 +285,25 @@ export default class HangingProtocolService extends PubSubService {
* @param protocolId - the id of the protocol * @param protocolId - the id of the protocol
* @returns protocol - the protocol with the given id * @returns protocol - the protocol with the given id
*/ */
public getProtocolById(protocolId: string): HangingProtocol.Protocol { public getProtocolById(protocolId: string, caseInsensitive = true): HangingProtocol.Protocol {
if (!protocolId) { if (!protocolId) {
return; return;
} }
if (protocolId === this.protocol?.id) { if (protocolId === this.protocol?.id) {
return this.protocol; return this.protocol;
} }
const protocol = this.protocols.get(protocolId);
let protocol = this.protocols.get(protocolId);
if (!protocol && caseInsensitive) {
const lowerCaseId = protocolId.toLowerCase();
for (const [key] of this.protocols) {
if (key.toLowerCase() === lowerCaseId) {
protocol = this.getProtocolById(key);
break;
}
}
}
if (!protocol) { if (!protocol) {
throw new Error(`No protocol ${protocolId} found`); throw new Error(`No protocol ${protocolId} found`);
} }
@ -533,8 +544,7 @@ export default class HangingProtocolService extends PubSubService {
} }
_validateProtocol(protocol: HangingProtocol.Protocol): HangingProtocol.Protocol { _validateProtocol(protocol: HangingProtocol.Protocol): HangingProtocol.Protocol {
protocol.id = protocol.id || protocol.name; protocol.name = protocol.name ?? protocol.id;
protocol.name = protocol.name || protocol.id;
const { stages } = protocol; const { stages } = protocol;
if (!stages) { if (!stages) {

View File

@ -15,7 +15,6 @@ be centered, and not draggable. They're commonly used when:
If you're curious about the DOs and DON'Ts of dialogs and modals, check out this If you're curious about the DOs and DON'Ts of dialogs and modals, check out this
article: ["Best Practices for Modals / Overlays / Dialog Windows"][ux-article] article: ["Best Practices for Modals / Overlays / Dialog Windows"][ux-article]
customComponent: The modal service allows users to provide their own Modal UI using the customComponents.
<div style={{padding:"56.25% 0 0 0", position:"relative"}}> <div style={{padding:"56.25% 0 0 0", position:"relative"}}>
@ -38,12 +37,17 @@ is expected to support, [check out it's interface in `@ohif/core`][interface]
| Implementation | Consumer | | Implementation | Consumer |
| ---------------------------------- | --------- | | ---------------------------------- | --------- |
| [Modal Provider][modal-provider]\* | Modal.jsx | | [Modal Provider][modal-provider]\* | Modal.jsx |
| customComponent | user extensions via setServiceImplementation({customComponent: Modal}) | | customComponent | user extensions via `setServiceImplementation({customComponent: Modal})` |
`*` - Denotes maintained by OHIF
### Custom Component
If you would like to customize the modal component that OHIF uses, you can register your own
component with the `customComponent` property.
```js
setServiceImplementation({customComponent: Modal})
```
> 3rd Party implementers may be added to this table via pull requests. > 3rd Party implementers may be added to this table via pull requests.

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import Numeric from '../../../../ui-next/src/components/Numeric'; import Numeric from '../../../../ui-next/src/components/Numeric';
import Icons from '../../../../ui-next/src/components/Icons'; import Icons from '../../../../ui-next/src/components/Icons';
import ShowcaseRow from './ShowcaseRow'; import ShowcaseRow from './ShowcaseRow';
@ -7,6 +7,9 @@ import ShowcaseRow from './ShowcaseRow';
* NumericShowcase component displays Numeric variants and examples * NumericShowcase component displays Numeric variants and examples
*/ */
export default function NumericShowcase() { export default function NumericShowcase() {
const [controlledValue, setControlledValue] = useState(0);
const [controlledValues, setControlledValues] = useState([0, 100] as [number, number]);
return ( return (
<div className="space-y-8"> <div className="space-y-8">
{/* Basic Number Input */} {/* Basic Number Input */}
@ -14,19 +17,26 @@ export default function NumericShowcase() {
title="Numeric - Number Input" title="Numeric - Number Input"
description="Basic number input with min, max and a label" description="Basic number input with min, max and a label"
code={` code={`
<Numeric.Container mode="number" min={0} max={10} onChange={onChange}> <Numeric.Container mode="number" min={0} max={10} onChange={val => console.debug('Value changed:', val)}>
<div className="flex flex-row items-center space-x-2"> <div className="flex flex-row items-center space-x-2">
<Numeric.Label>Width</Numeric.Label> <Numeric.Label>Width</Numeric.Label>
<Numeric.NumberInput /> <Numeric.NumberInput />
</div> </div>
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="number" min={0} max={100} onChange={onChange}> <Numeric.Container mode="number" className="space-y-1" min={0} max={100} onChange={val => console.debug('Value changed:', val)}>
<Numeric.Label className="text-secondary-foreground text-sm font-bold">Bolder</Numeric.Label> <Numeric.Label className="text-muted-foreground text-sm font-bold">Bolder</Numeric.Label>
<Numeric.NumberInput className="w-12" /> <Numeric.NumberInput className="w-12" />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="number" className="flex flex-row items-center justify-between" onChange={onChange} min={0} value={123465789} max={10000000000000}> <Numeric.Container
mode="number"
className="flex flex-row items-center justify-between"
onChange={val => console.debug('Value changed:', val)}
min={0}
value={123465789}
max={10000000000000}
>
<Numeric.Label className="flex flex-row items-center"> <Numeric.Label className="flex flex-row items-center">
<Icons.Add /> <Icons.Add />
With Icon With Icon
@ -82,18 +92,37 @@ export default function NumericShowcase() {
title="Numeric - Single Range" title="Numeric - Single Range"
description="Single range slider with optional number input" description="Single range slider with optional number input"
code={` code={`
<Numeric.Container mode="singleRange" min={0} max={100} step={1} value={50} onChange={onChange}> // For controlled component
const [controlledValue, setControlledValue] = useState(0);
<Numeric.Container mode="singleRange" min={0} max={100} onChange={val => console.debug('Value changed:', val)}>
<Numeric.Label>Brightness</Numeric.Label> <Numeric.Label>Brightness</Numeric.Label>
<Numeric.SingleRange showNumberInput /> <Numeric.SingleRange showNumberInput />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="singleRange" min={-50} max={50} step={1} value={0} className="flex flex-row items-center" onChange={onChange}> <Numeric.Container
mode="singleRange"
min={-50}
max={50}
step={1}
defaultValue={0}
className="flex flex-row items-center"
onChange={val => console.debug('Value changed:', val)}
>
<Numeric.Label showValue>Contrast</Numeric.Label> <Numeric.Label showValue>Contrast</Numeric.Label>
<Numeric.SingleRange /> <Numeric.SingleRange />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="singleRange" min={0} max={100} step={1} value={50} className="flex flex-row items-center space-x-2" onChange={onChange}> <Numeric.Container
<Numeric.Label>Something Else </Numeric.Label> mode="singleRange"
min={0}
max={100}
step={1}
value={controlledValue}
className="flex flex-row items-center space-x-2"
onChange={val => setControlledValue(val as number)}
>
<Numeric.Label>Controlled State (Parent) </Numeric.Label>
<Numeric.SingleRange showNumberInput /> <Numeric.SingleRange showNumberInput />
</Numeric.Container>`} </Numeric.Container>`}
> >
@ -102,8 +131,6 @@ export default function NumericShowcase() {
mode="singleRange" mode="singleRange"
min={0} min={0}
max={100} max={100}
step={1}
value={50}
onChange={val => console.debug('Value changed:', val)} onChange={val => console.debug('Value changed:', val)}
> >
<Numeric.Label>Brightness</Numeric.Label> <Numeric.Label>Brightness</Numeric.Label>
@ -115,7 +142,7 @@ export default function NumericShowcase() {
min={-50} min={-50}
max={50} max={50}
step={1} step={1}
value={0} defaultValue={0}
className="flex flex-row items-center" className="flex flex-row items-center"
onChange={val => console.debug('Value changed:', val)} onChange={val => console.debug('Value changed:', val)}
> >
@ -128,11 +155,11 @@ export default function NumericShowcase() {
min={0} min={0}
max={100} max={100}
step={1} step={1}
value={50} value={controlledValue}
className="flex flex-row items-center space-x-2" className="flex flex-row items-center space-x-2"
onChange={val => console.debug('Value changed:', val)} onChange={val => setControlledValue(val as number)}
> >
<Numeric.Label>Something Else </Numeric.Label> <Numeric.Label>Controlled State (Parent) </Numeric.Label>
<Numeric.SingleRange showNumberInput /> <Numeric.SingleRange showNumberInput />
</Numeric.Container> </Numeric.Container>
</div> </div>
@ -143,18 +170,44 @@ export default function NumericShowcase() {
title="Numeric - Double Range" title="Numeric - Double Range"
description="Double range slider for selecting a range of values" description="Double range slider for selecting a range of values"
code={` code={`
<Numeric.Container mode="doubleRange" min={0} max={100} step={1} values={[30, 70]} onChange={onChange}> // For controlled component
const [controlledValues, setControlledValues] = useState<[number, number]>([0, 100]);
<Numeric.Container
mode="doubleRange"
min={0}
max={100}
step={1}
className="space-y-1"
onChange={vals => console.debug('Values changed:', vals)}
>
<Numeric.Label showValue>Window Width/Level</Numeric.Label> <Numeric.Label showValue>Window Width/Level</Numeric.Label>
<Numeric.DoubleRange /> <Numeric.DoubleRange />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="doubleRange" min={0} max={100} step={1} values={[30, 70]}> <Numeric.Container
mode="doubleRange"
min={0}
max={100}
step={1}
defaultValues={[30, 70]}
className="space-y-1"
onChange={vals => console.debug('Values changed:', vals)}
>
<Numeric.Label>Window Width/Level</Numeric.Label> <Numeric.Label>Window Width/Level</Numeric.Label>
<Numeric.DoubleRange showNumberInputs /> <Numeric.DoubleRange showNumberInputs />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="doubleRange" min={0} max={100} step={1} values={[30, 70]} className="flex flex-row items-center space-x-2" onChange={onChange}> <Numeric.Container
<Numeric.Label>Inline double slider</Numeric.Label> mode="doubleRange"
min={0}
max={100}
step={1}
values={controlledValues}
className="flex flex-row items-center space-x-2"
onChange={vals => setControlledValues(vals as [number, number])}
>
<Numeric.Label>Controlled State (Parent) </Numeric.Label>
<Numeric.DoubleRange /> <Numeric.DoubleRange />
</Numeric.Container>`} </Numeric.Container>`}
> >
@ -164,7 +217,6 @@ export default function NumericShowcase() {
min={0} min={0}
max={100} max={100}
step={1} step={1}
values={[30, 70]}
className="space-y-1" className="space-y-1"
onChange={vals => console.debug('Values changed:', vals)} onChange={vals => console.debug('Values changed:', vals)}
> >
@ -177,8 +229,9 @@ export default function NumericShowcase() {
min={0} min={0}
max={100} max={100}
step={1} step={1}
values={[30, 70]} defaultValues={[30, 70]}
className="space-y-1" className="space-y-1"
onChange={vals => console.debug('Values changed:', vals)}
> >
<Numeric.Label>Window Width/Level</Numeric.Label> <Numeric.Label>Window Width/Level</Numeric.Label>
<Numeric.DoubleRange showNumberInputs /> <Numeric.DoubleRange showNumberInputs />
@ -189,11 +242,11 @@ export default function NumericShowcase() {
min={0} min={0}
max={100} max={100}
step={1} step={1}
values={[30, 70]} values={controlledValues}
className="flex flex-row items-center space-x-2" className="flex flex-row items-center space-x-2"
onChange={vals => console.debug('Values changed:', vals)} onChange={vals => setControlledValues(vals as [number, number])}
> >
<Numeric.Label>Inline double slider</Numeric.Label> <Numeric.Label>Controlled State (Parent) </Numeric.Label>
<Numeric.DoubleRange /> <Numeric.DoubleRange />
</Numeric.Container> </Numeric.Container>
</div> </div>
@ -204,17 +257,35 @@ export default function NumericShowcase() {
title="Numeric - Combined Examples" title="Numeric - Combined Examples"
description="Different modes and configurations working together" description="Different modes and configurations working together"
code={` code={`
<Numeric.Container mode="number" min={0} max={10} step={0.1}> <Numeric.Container
mode="number"
min={0}
max={10}
step={0.1}
className="space-y-1"
>
<Numeric.Label>Zoom Factor</Numeric.Label> <Numeric.Label>Zoom Factor</Numeric.Label>
<Numeric.NumberInput /> <Numeric.NumberInput />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="singleRange" min={0} max={360} step={1}> <Numeric.Container
mode="singleRange"
min={0}
max={360}
step={1}
className="space-y-1"
>
<Numeric.Label showValue>Rotation</Numeric.Label> <Numeric.Label showValue>Rotation</Numeric.Label>
<Numeric.SingleRange showNumberInput /> <Numeric.SingleRange showNumberInput />
</Numeric.Container> </Numeric.Container>
<Numeric.Container mode="doubleRange" min={-1000} max={3000} values={[1000, 2000]} step={10}> <Numeric.Container
mode="doubleRange"
min={-1000}
max={3000}
step={10}
className="space-y-1"
>
<Numeric.Label showValue>CT Window</Numeric.Label> <Numeric.Label showValue>CT Window</Numeric.Label>
<Numeric.DoubleRange showNumberInputs /> <Numeric.DoubleRange showNumberInputs />
</Numeric.Container>`} </Numeric.Container>`}
@ -246,7 +317,6 @@ export default function NumericShowcase() {
mode="doubleRange" mode="doubleRange"
min={-1000} min={-1000}
max={3000} max={3000}
values={[1000, 2000]}
step={10} step={10}
className="space-y-1" className="space-y-1"
> >

View File

@ -1,5 +1,6 @@
// Numeric.tsx // Numeric.tsx
import React, { createContext, useContext, useState, useCallback, PropsWithChildren } from 'react'; import React, { createContext, useContext, useCallback, PropsWithChildren } from 'react';
import { useControllableState } from '@radix-ui/react-use-controllable-state';
import { cn } from '../../lib/utils'; import { cn } from '../../lib/utils';
import { Input } from '../Input/Input'; import { Input } from '../Input/Input';
import { Slider } from '../Slider/Slider'; import { Slider } from '../Slider/Slider';
@ -23,8 +24,10 @@ const NumericMetaContext = createContext<NumericMetaContextValue | null>(null);
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
interface NumericMetaContainerProps { interface NumericMetaContainerProps {
mode: 'number' | 'singleRange' | 'doubleRange'; mode: 'number' | 'singleRange' | 'doubleRange';
value?: number; // for single-value usage value?: number; // for controlled single-value usage from parent
values?: [number, number]; // for double-range usage defaultValue?: number; // for uncontrolled single-value usage
values?: [number, number]; // for controlled double-range usage from parent
defaultValues?: [number, number]; // for uncontrolled double-range usage
onChange?: (val: number | [number, number]) => void; onChange?: (val: number | [number, number]) => void;
min?: number; min?: number;
max?: number; max?: number;
@ -34,8 +37,10 @@ interface NumericMetaContainerProps {
function NumericMetaContainer({ function NumericMetaContainer({
mode, mode,
value = 0, value,
values = [0, 100], defaultValue,
values,
defaultValues,
onChange, onChange,
min = 0, min = 0,
max = 100, max = 100,
@ -43,26 +48,46 @@ function NumericMetaContainer({
className, className,
children, children,
}: PropsWithChildren<NumericMetaContainerProps>) { }: PropsWithChildren<NumericMetaContainerProps>) {
// Initialize state with props but don't update automatically // Calculate default values based on min and max
const [internalSingleValue, setInternalSingleValue] = useState<number>(value); const calculatedDefaultValue = defaultValue ?? min + (max - min) / 2;
const [internalDoubleValue, setInternalDoubleValue] = useState<[number, number]>(values); const calculatedDefaultValues = defaultValues ?? [
min + (max - min) * 0.3,
min + (max - min) * 0.7,
];
// Use useControllableState for both single and double values
const [internalSingleValue, setInternalSingleValue] = useControllableState({
prop: mode === 'number' || mode === 'singleRange' ? value : undefined,
defaultProp: calculatedDefaultValue,
onChange: newVal => {
if (mode === 'number' || mode === 'singleRange') {
onChange?.(newVal);
}
},
});
const [internalDoubleValue, setInternalDoubleValue] = useControllableState({
prop: mode === 'doubleRange' ? values : undefined,
defaultProp: calculatedDefaultValues,
onChange: newVals => {
if (mode === 'doubleRange') {
onChange?.(newVals);
}
},
});
const handleSingleChange = useCallback( const handleSingleChange = useCallback(
(newVal: number) => { (newVal: number) => {
setInternalSingleValue(newVal); setInternalSingleValue(newVal);
onChange?.(newVal);
}, },
[onChange] [setInternalSingleValue]
); );
const handleDoubleChange = useCallback( const handleDoubleChange = useCallback(
(newVals: [number, number]) => { (newVals: [number, number]) => {
// Update internal state
setInternalDoubleValue(newVals); setInternalDoubleValue(newVals);
// Notify parent if onChange is provided
onChange?.(newVals);
}, },
[onChange] [setInternalDoubleValue]
); );
return ( return (

View File

@ -99,6 +99,7 @@ import {
ToolButtonListItem, ToolButtonListItem,
ToolButtonListDivider, ToolButtonListDivider,
Toolbox, Toolbox,
Numeric,
} from './components'; } from './components';
import { DataRow } from './components/DataRow'; import { DataRow } from './components/DataRow';
@ -223,4 +224,5 @@ export {
Toolbox, Toolbox,
useToolbox, useToolbox,
utils, utils,
Numeric,
}; };

View File

@ -19,8 +19,8 @@ export type CinePlayerProps = {
onClose: () => void; onClose: () => void;
updateDynamicInfo?: () => void; updateDynamicInfo?: () => void;
dynamicInfo?: { dynamicInfo?: {
timePointIndex: number; dimensionGroupNumber: number;
numTimePoints: number; numDimensionGroups: number;
label?: string; label?: string;
}; };
}; };
@ -41,7 +41,7 @@ const CinePlayer: React.FC<CinePlayerProps> = ({
dynamicInfo = {}, dynamicInfo = {},
updateDynamicInfo, updateDynamicInfo,
}) => { }) => {
const isDynamic = !!dynamicInfo?.numTimePoints; const isDynamic = !!dynamicInfo?.numDimensionGroups;
const [frameRate, setFrameRate] = useState(defaultFrameRate); const [frameRate, setFrameRate] = useState(defaultFrameRate);
const debouncedSetFrameRate = useCallback(debounce(onFrameRateChange, 100), [onFrameRateChange]); const debouncedSetFrameRate = useCallback(debounce(onFrameRateChange, 100), [onFrameRateChange]);
@ -59,14 +59,14 @@ const CinePlayer: React.FC<CinePlayerProps> = ({
setFrameRate(defaultFrameRate); setFrameRate(defaultFrameRate);
}, [defaultFrameRate]); }, [defaultFrameRate]);
const handleTimePointChange = useCallback( const handleDimensionGroupNumberChange = useCallback(
(newIndex: number) => { (newGroupNumber: number) => {
if (isDynamic && dynamicInfo) { if (isDynamic && dynamicInfo) {
// Here, you would update the component's state or context that controls the current time point index // Here, you would update the component's state or context that controls the current time point index
// For demonstration, assuming a hypothetical function that updates the time point index // For demonstration, assuming a hypothetical function that updates the time point index
updateDynamicInfo({ updateDynamicInfo({
...dynamicInfo, ...dynamicInfo,
timePointIndex: newIndex, dimensionGroupNumber: newGroupNumber,
}); });
} }
}, },
@ -77,10 +77,10 @@ const CinePlayer: React.FC<CinePlayerProps> = ({
<div className={className}> <div className={className}>
{isDynamic && dynamicInfo && ( {isDynamic && dynamicInfo && (
<InputRange <InputRange
value={dynamicInfo.timePointIndex} value={dynamicInfo.dimensionGroupNumber}
onChange={handleTimePointChange} onChange={handleDimensionGroupNumberChange}
minValue={0} minValue={1}
maxValue={dynamicInfo.numTimePoints - 1} maxValue={dynamicInfo.numDimensionGroups}
step={1} step={1}
containerClassName="mb-3 w-full" containerClassName="mb-3 w-full"
labelClassName="text-xs text-white" labelClassName="text-xs text-white"
@ -107,8 +107,8 @@ const CinePlayer: React.FC<CinePlayerProps> = ({
<div className="min-w-16 max-w-44 flex flex-col text-white"> <div className="min-w-16 max-w-44 flex flex-col text-white">
{/* Add Tailwind classes for monospace font and center alignment */} {/* Add Tailwind classes for monospace font and center alignment */}
<div className="text-[11px]"> <div className="text-[11px]">
<span className="w-2 text-white">{dynamicInfo.timePointIndex}</span>{' '} <span className="w-2 text-white">{dynamicInfo.dimensionGroupNumber}</span>{' '}
<span className="text-aqua-pale">{`/${dynamicInfo.numTimePoints}`}</span> <span className="text-aqua-pale">{`/${dynamicInfo.numDimensionGroups}`}</span>
</div> </div>
<div className="text-aqua-pale text-xs">{dynamicInfo.label}</div> <div className="text-aqua-pale text-xs">{dynamicInfo.label}</div>
</div> </div>
@ -180,8 +180,8 @@ CinePlayer.propTypes = {
onClose: PropTypes.func, onClose: PropTypes.func,
isDynamic: PropTypes.bool, isDynamic: PropTypes.bool,
dynamicInfo: PropTypes.shape({ dynamicInfo: PropTypes.shape({
timePointIndex: PropTypes.number, dimensionGroupNumber: PropTypes.number,
numTimePoints: PropTypes.number, numDimensionGroups: PropTypes.number,
label: PropTypes.string, label: PropTypes.string,
}), }),
}; };

View File

@ -1,9 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Types } from '@ohif/core';
import MeasurementItem from './MeasurementItem';
const MeasurementTable = ({ const MeasurementTable = ({
data = [], data = [],
@ -17,9 +14,9 @@ const MeasurementTable = ({
const { t } = useTranslation('MeasurementTable'); const { t } = useTranslation('MeasurementTable');
const amount = data.length; const amount = data.length;
const itemCustomization = customizationService.getCustomization('MeasurementItem'); const CustomMeasurementItem = customizationService.getCustomization(
'microscopyPanel.measurementItem'
const CustomMeasurementItem = itemCustomization.content; );
const onMeasurementDeleteHandler = ({ uid }) => { const onMeasurementDeleteHandler = ({ uid }) => {
const measurement = measurementService.getMeasurement(uid); const measurement = measurementService.getMeasurement(uid);

View File

@ -1393,10 +1393,10 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cornerstonejs/adapters@^2.17.2": "@cornerstonejs/adapters@^2.19.3":
version "2.17.2" version "2.19.3"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.17.2.tgz#a6fd4fc24bd8820faa171d56c3917e73d9da1de7" resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.19.3.tgz#237f4e1adae5f2b77a17426ebbbb601fe65b2bbe"
integrity sha512-XPOdTU1dbPIFSH/51y/nSvcFKXGc5xJyOqhsArjPrhGfhShEqXguvXvvTG01XH4rpX6BXfOuHEf66DLSB9Axxg== integrity sha512-QuugcUCelTW9bxhO1yewuuf6UHbIufiWMU+plNp40RwR92hgWi1SB9K/gFhtSRxVBqnkbG3Sh6mZRSuS3KcP1A==
dependencies: dependencies:
"@babel/runtime-corejs2" "^7.17.8" "@babel/runtime-corejs2" "^7.17.8"
buffer "^6.0.3" buffer "^6.0.3"
@ -1429,19 +1429,19 @@
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0" resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg== integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
"@cornerstonejs/core@^2.17.2": "@cornerstonejs/core@^2.19.3":
version "2.17.2" version "2.19.3"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.17.2.tgz#0ce18b3efd94ecbd99778f5d60afe25772528035" resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.19.3.tgz#709eb794f26be6b768964b1546dcdd42a62686af"
integrity sha512-NjQHVXI2bfiNDUv4R0qOsWiL/rdgZMzgPLKsF9nNgji2GS+3wUZsdjXZgd5esD3nIENExZRFWYCCSMVhg+9sxA== integrity sha512-yqPFpfzKCNj9U94q1do8oE3adg7+/t+bc4uBHrNPCvbUyOqaWZzentw5+79cj5hhHif2OG0jVNRSPr+kbBBk2Q==
dependencies: dependencies:
"@kitware/vtk.js" "32.9.0" "@kitware/vtk.js" "32.9.0"
comlink "^4.4.1" comlink "^4.4.1"
gl-matrix "^3.4.3" gl-matrix "^3.4.3"
"@cornerstonejs/dicom-image-loader@^2.17.2": "@cornerstonejs/dicom-image-loader@^2.19.3":
version "2.17.2" version "2.19.3"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.17.2.tgz#8abf7f6467cce265349f452ff43b0a39c1a95726" resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.19.3.tgz#10d4fe3bdee3c2f255d7f55c70b59760f26d84f1"
integrity sha512-SjOSe9RLVoX2Qj6nQEhkuuphiWX4mq67dr5JMcKifEUe8TCBRECpxHcUc7G4QuVkazR7teQLt0JD8h4yqQ5hTQ== integrity sha512-/VTmaDabIqF8lBzPq0yK3yF6TIb3vTEoMeyvXTQWpPG1wjiTRAaYql5uQjCgE1p/xCXVA3Iq+h2rk90HWFu6nA==
dependencies: dependencies:
"@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-charls" "^1.2.3"
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
@ -1452,10 +1452,10 @@
pako "^2.0.4" pako "^2.0.4"
uuid "^9.0.0" uuid "^9.0.0"
"@cornerstonejs/tools@^2.17.2": "@cornerstonejs/tools@^2.19.3":
version "2.17.2" version "2.19.3"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.17.2.tgz#c2ef6b776dd53915ad35f6336643ade97c220093" resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.19.3.tgz#1f4a7045298772184e95043b99ff98ce5ae6686e"
integrity sha512-IuS4P3ErxQ8o+SFnpPiZvtvHTA4aN2hwGn5BwuAZScZkBcOgEGAGJ3FBjFcV0fzZBvIORG5KCwUK82HxTQ1b8w== integrity sha512-bJFhE2b1B2k8enZT9vZqspLXmSHqCLAOFwib5FWi4/9AtNydVaDBIafAYq/gCXTcF8YcbsUhBhWQL1LU7ejkWg==
dependencies: dependencies:
"@types/offscreencanvas" "2019.7.3" "@types/offscreencanvas" "2019.7.3"
comlink "^4.4.1" comlink "^4.4.1"