fix: jump to measurement forever (#4867)
This commit is contained in:
parent
eafa2efda5
commit
d7bd36544a
318
bun.lock
318
bun.lock
@ -33,7 +33,7 @@
|
||||
},
|
||||
"addOns/externals/devDependencies": {
|
||||
"name": "@externals/devDependencies",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
@ -121,21 +121,21 @@
|
||||
},
|
||||
"addOns/externals/dicom-microscopy-viewer": {
|
||||
"name": "@externals/dicom-microscopy-viewer",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"dicom-microscopy-viewer": "^0.46.1",
|
||||
},
|
||||
},
|
||||
"extensions/cornerstone": {
|
||||
"name": "@ohif/extension-cornerstone",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.16",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.17",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
@ -152,9 +152,9 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -166,19 +166,19 @@
|
||||
},
|
||||
"extensions/cornerstone-dicom-pmap": {
|
||||
"name": "@ohif/extension-cornerstone-dicom-pmap",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@ -189,16 +189,16 @@
|
||||
},
|
||||
"extensions/cornerstone-dicom-rt": {
|
||||
"name": "@ohif/extension-cornerstone-dicom-rt",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"react-color": "^2.19.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@ -209,19 +209,19 @@
|
||||
},
|
||||
"extensions/cornerstone-dicom-seg": {
|
||||
"name": "@ohif/extension-cornerstone-dicom-seg",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@ -232,19 +232,19 @@
|
||||
},
|
||||
"extensions/cornerstone-dicom-sr": {
|
||||
"name": "@ohif/extension-cornerstone-dicom-sr",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -254,19 +254,19 @@
|
||||
},
|
||||
"extensions/cornerstone-dynamic-volume": {
|
||||
"name": "@ohif/extension-cornerstone-dynamic-volume",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -276,7 +276,7 @@
|
||||
},
|
||||
"extensions/default": {
|
||||
"name": "@ohif/extension-default",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||
@ -284,8 +284,8 @@
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicomweb-client": "^0.10.4",
|
||||
"prop-types": "^15.6.2",
|
||||
@ -299,7 +299,7 @@
|
||||
},
|
||||
"extensions/dicom-microscopy": {
|
||||
"name": "@ohif/extension-dicom-microscopy",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/codec-charls": "^1.2.3",
|
||||
@ -310,10 +310,10 @@
|
||||
"mathjs": "^12.4.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@ -324,14 +324,14 @@
|
||||
},
|
||||
"extensions/dicom-pdf": {
|
||||
"name": "@ohif/extension-dicom-pdf",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -341,14 +341,14 @@
|
||||
},
|
||||
"extensions/dicom-video": {
|
||||
"name": "@ohif/extension-dicom-video",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -358,20 +358,20 @@
|
||||
},
|
||||
"extensions/measurement-tracking": {
|
||||
"name": "@ohif/extension-measurement-tracking",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"@xstate/react": "^3.2.2",
|
||||
"xstate": "^4.10.0",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"classnames": "^2.3.2",
|
||||
"dcmjs": "*",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
@ -384,14 +384,14 @@
|
||||
},
|
||||
"extensions/test-extension": {
|
||||
"name": "@ohif/extension-test",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "0.38.0",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -401,14 +401,14 @@
|
||||
},
|
||||
"extensions/tmtv": {
|
||||
"name": "@ohif/extension-tmtv",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"classnames": "^2.3.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@ -418,7 +418,7 @@
|
||||
},
|
||||
"modes/basic-dev-mode": {
|
||||
"name": "@ohif/mode-basic-dev-mode",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
@ -428,17 +428,17 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/basic-test-mode": {
|
||||
"name": "@ohif/mode-test",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
@ -448,19 +448,19 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.139",
|
||||
"@ohif/extension-test": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.140",
|
||||
"@ohif/extension-test": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/longitudinal": {
|
||||
"name": "@ohif/mode-longitudinal",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
@ -470,32 +470,32 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/microscopy": {
|
||||
"name": "@ohif/mode-microscopy",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/preclinical-4d": {
|
||||
"name": "@ohif/mode-preclinical-4d",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
},
|
||||
@ -504,17 +504,17 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-tmtv": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-tmtv": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/segmentation": {
|
||||
"name": "@ohif/mode-segmentation",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
@ -546,19 +546,19 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"modes/tmtv": {
|
||||
"name": "@ohif/mode-tmtv",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next": "^17.0.3",
|
||||
@ -568,43 +568,43 @@
|
||||
"webpack-merge": "^5.7.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.140",
|
||||
},
|
||||
},
|
||||
"platform/app": {
|
||||
"name": "@ohif/app",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/codec-charls": "^1.2.3",
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@emotion/serialize": "^1.1.3",
|
||||
"@ohif/core": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.139",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.139",
|
||||
"@ohif/extension-default": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.139",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.139",
|
||||
"@ohif/extension-test": "3.10.0-beta.139",
|
||||
"@ohif/i18n": "3.10.0-beta.139",
|
||||
"@ohif/mode-basic-dev-mode": "3.10.0-beta.139",
|
||||
"@ohif/mode-longitudinal": "3.10.0-beta.139",
|
||||
"@ohif/mode-microscopy": "3.10.0-beta.139",
|
||||
"@ohif/mode-test": "3.10.0-beta.139",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@ohif/ui-next": "3.10.0-beta.139",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.140",
|
||||
"@ohif/extension-dicom-video": "3.10.0-beta.140",
|
||||
"@ohif/extension-test": "3.10.0-beta.140",
|
||||
"@ohif/i18n": "3.10.0-beta.140",
|
||||
"@ohif/mode-basic-dev-mode": "3.10.0-beta.140",
|
||||
"@ohif/mode-longitudinal": "3.10.0-beta.140",
|
||||
"@ohif/mode-microscopy": "3.10.0-beta.140",
|
||||
"@ohif/mode-test": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"@ohif/ui-next": "3.10.0-beta.140",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@types/react": "^18.3.3",
|
||||
"classnames": "^2.3.2",
|
||||
@ -645,7 +645,7 @@
|
||||
},
|
||||
"platform/cli": {
|
||||
"name": "@ohif/cli",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"bin": {
|
||||
"ohif-cli": "src/index.js",
|
||||
},
|
||||
@ -669,7 +669,7 @@
|
||||
},
|
||||
"platform/core": {
|
||||
"name": "@ohif/core",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"dcmjs": "*",
|
||||
@ -694,15 +694,15 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@ohif/ui": "3.10.0-beta.139",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"cornerstone-math": "0.1.9",
|
||||
"dicom-parser": "^1.8.21",
|
||||
},
|
||||
},
|
||||
"platform/i18n": {
|
||||
"name": "@ohif/i18n",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"i18next-locize-backend": "^2.0.0",
|
||||
@ -727,7 +727,7 @@
|
||||
},
|
||||
"platform/ui": {
|
||||
"name": "@ohif/ui",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@testing-library/react": "^13.1.0",
|
||||
"browser-detect": "^0.2.28",
|
||||
@ -787,7 +787,7 @@
|
||||
},
|
||||
"platform/ui-next": {
|
||||
"name": "@ohif/ui-next",
|
||||
"version": "3.10.0-beta.139",
|
||||
"version": "3.10.0-beta.140",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-accordion": "^1.2.0",
|
||||
"@radix-ui/react-checkbox": "^1.1.1",
|
||||
@ -1095,7 +1095,7 @@
|
||||
|
||||
"@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
|
||||
|
||||
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.7.16", "", { "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": "^3.7.16", "@cornerstonejs/tools": "^3.7.16" } }, "sha512-gMLRTZzhIGOwUT9rufpv4uq5iHTJgg2x6GW++eOi/6bEDY2wOiH2peRM8W1EfAoa3cK+lLLoAqEARlVMJq//tg=="],
|
||||
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.7.17", "", { "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": "^3.7.17", "@cornerstonejs/tools": "^3.7.17" } }, "sha512-K1tz4y5YRgen+z8Yva5mzO3iwn1UZRoqf0wX8VjU1zszx/F4m19DSNcR9H5BJvlGM09DZjpJ42QXK2o9pIvnTg=="],
|
||||
|
||||
"@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="],
|
||||
|
||||
@ -1107,15 +1107,15 @@
|
||||
|
||||
"@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
|
||||
|
||||
"@cornerstonejs/core": ["@cornerstonejs/core@3.7.16", "", { "dependencies": { "@kitware/vtk.js": "32.12.1", "comlink": "^4.4.1", "gl-matrix": "^3.4.3", "loglevel": "^1.9.2" } }, "sha512-5rc371p1P+hk1rUzpHTByW+7Mp6LyahqWJLJwt/55a4BEiEtbhWyTSAz/XKWcOd5bgq7huAsyHKCmMcWrHx3pg=="],
|
||||
"@cornerstonejs/core": ["@cornerstonejs/core@3.7.17", "", { "dependencies": { "@kitware/vtk.js": "32.12.1", "comlink": "^4.4.1", "gl-matrix": "^3.4.3", "loglevel": "^1.9.2" } }, "sha512-2Z3FqrGJept9k1dmlGeMBPon1MDR/P7CkcTTevpKTlYiT3D7bqQ+Q5xdssLzWRD86et0PkRSJGktBM163WCgGw=="],
|
||||
|
||||
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.7.16", "", { "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", "dicom-parser": "^1.8.9", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.16" } }, "sha512-8O3cd9L54s3AFE3DZUMKOUvuuE9MkYuWZ8NgCPtBE1Qky6d4KNGKdljzwmpj8JJ7y7yGLW1rI0KqQc9DCf4//Q=="],
|
||||
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.7.17", "", { "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", "dicom-parser": "^1.8.9", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.17" } }, "sha512-LKHQ7x7S47TtF8M4ZmR4S+afbSsAT+yVMkKD81VU3A8oyuX7hT4+cUO4JlGGck3BxG4FyjgNSGT+T3YxAH1SHw=="],
|
||||
|
||||
"@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@3.7.16", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.16", "@cornerstonejs/tools": "^3.7.16", "@kitware/vtk.js": "32.12.1" } }, "sha512-zoL7arbPywNxUksKkkorcICpIwAgcpYbBBEFIGXt4gSS7NPC7cRU12PU1mj3Cgy+59nO2QIohoPkv0Kj/AwXmA=="],
|
||||
"@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@3.7.17", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.17", "@cornerstonejs/tools": "^3.7.17", "@kitware/vtk.js": "32.12.1" } }, "sha512-K8R11wqv4TFljMArbx+4JbMtsINeMandp0mD8zyrj1rWXA+RY49QcNa7ob6KBnV26xJqXMT0VyJ0k/Ow53TiLQ=="],
|
||||
|
||||
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.7.16", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.16", "@cornerstonejs/tools": "^3.7.16", "@kitware/vtk.js": "32.12.1" } }, "sha512-HW7h9xRWRDKmaYpv4KWqSYcFz4M2EbMnYNaP+JgnLRws/1eoVPM5YYTsWgyINOM8fdR9o6tMmtMdjcioEGsZPg=="],
|
||||
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.7.17", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.17", "@cornerstonejs/tools": "^3.7.17", "@kitware/vtk.js": "32.12.1" } }, "sha512-ZI0643arqYbkrjadDSOsGTO2JS1OUtJkF8qEnjjG8MlxqQ7g6sPnTM/atrYRc9ZFoJxFL4kz7D0gOjcBrarYeQ=="],
|
||||
|
||||
"@cornerstonejs/tools": ["@cornerstonejs/tools@3.7.16", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.16", "@kitware/vtk.js": "32.12.1", "@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-hmAAmUiEr8z920btZtkT7jqYgZzQqLT82FijfYZVd591nddR25hb77OXEJ+PPAQbvktwPSUZx0kMBoUuM5VpWw=="],
|
||||
"@cornerstonejs/tools": ["@cornerstonejs/tools@3.7.17", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.7.17", "@kitware/vtk.js": "32.12.1", "@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-ZDMboShGzMDkqnzEDE7Y9UTJgHqGkVQt8l6AL5dCyA/IIlWEXXdxVe1weotJxgjMqaPETiwJ5EtN/3D4+tf1Rg=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
|
||||
@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@ -46,9 +46,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,28 +77,4 @@ export default function init({
|
||||
SRRectangleROI: dashedLine,
|
||||
global: {},
|
||||
});
|
||||
|
||||
measurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_LAYOUT,
|
||||
({ viewportId, measurement, isConsumed }) => {
|
||||
if (isConsumed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const currentViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
const { viewPlaneNormal } = currentViewport.getCamera();
|
||||
const referencedImageId = csToolsUtils.getClosestImageIdForStackViewport(
|
||||
currentViewport as StackViewport,
|
||||
measurement.points[0],
|
||||
viewPlaneNormal
|
||||
);
|
||||
const imageIndex = (currentViewport as StackViewport)
|
||||
.getImageIds()
|
||||
.indexOf(referencedImageId);
|
||||
csUtils.jumpToSlice(currentViewport.element, { imageIndex });
|
||||
} catch (error) {
|
||||
console.warn('Unable to jump to image based on measurement coordinate', error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"dcmjs": "*",
|
||||
@ -51,11 +51,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.16",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/adapters": "^3.7.17",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/labelmap-interpolation": "^3.7.17",
|
||||
"@cornerstonejs/polymorphic-segmentation": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "32.12.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
|
||||
@ -23,12 +23,6 @@ import { WITH_NAVIGATION } from '../services/ViewportService/CornerstoneViewport
|
||||
|
||||
const STACK = 'stack';
|
||||
|
||||
/**
|
||||
* Caches the jump to measurement operation, so that if display set is shown,
|
||||
* it can jump to the measurement.
|
||||
*/
|
||||
let cacheJumpToMeasurementEvent;
|
||||
|
||||
// Todo: This should be done with expose of internal API similar to react-vtkjs-viewport
|
||||
// Then we don't need to worry about the re-renders if the props change.
|
||||
const OHIFCornerstoneViewport = React.memo(
|
||||
@ -99,6 +93,7 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
cornerstoneCacheService,
|
||||
viewportActionCornersService,
|
||||
customizationService,
|
||||
measurementService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const [viewportDialogState] = useViewportDialog();
|
||||
@ -263,14 +258,6 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
|
||||
const presentations = getViewportPresentations(viewportId, viewportOptions);
|
||||
|
||||
let measurement;
|
||||
if (cacheJumpToMeasurementEvent?.viewportId === viewportId) {
|
||||
measurement = cacheJumpToMeasurementEvent.measurement;
|
||||
// Delete the position presentation so that viewport navigates direct
|
||||
presentations.positionPresentation = null;
|
||||
cacheJumpToMeasurementEvent = null;
|
||||
}
|
||||
|
||||
// Note: This is a hack to get the grid to re-render the OHIFCornerstoneViewport component
|
||||
// Used for segmentation hydration right now, since the logic to decide whether
|
||||
// a viewport needs to render a segmentation lives inside the CornerstoneViewportService
|
||||
@ -288,10 +275,6 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
displaySetOptions,
|
||||
presentations
|
||||
);
|
||||
|
||||
if (measurement) {
|
||||
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
|
||||
}
|
||||
};
|
||||
|
||||
loadViewportData();
|
||||
@ -312,16 +295,13 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
return;
|
||||
}
|
||||
|
||||
const unsubscribeFromJumpToMeasurementEvents = _subscribeToJumpToMeasurementEvents(
|
||||
elementRef,
|
||||
viewportId,
|
||||
servicesManager
|
||||
const { unsubscribe } = measurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
|
||||
event => handleJumpToMeasurement(event, elementRef, viewportId, cornerstoneViewportService)
|
||||
);
|
||||
|
||||
_checkForCachedJumpToMeasurementEvents(elementRef, viewportId, displaySets, servicesManager);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromJumpToMeasurementEvents();
|
||||
unsubscribe();
|
||||
};
|
||||
}, [displaySets, elementRef, viewportId, isJumpToMeasurementDisabled, servicesManager]);
|
||||
|
||||
@ -427,99 +407,52 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
areEqual
|
||||
);
|
||||
|
||||
function _subscribeToJumpToMeasurementEvents(elementRef, viewportId, servicesManager) {
|
||||
const { measurementService, cornerstoneViewportService } = servicesManager.services;
|
||||
// Helper function to handle jumping to measurements
|
||||
function handleJumpToMeasurement(event, elementRef, viewportId, cornerstoneViewportService) {
|
||||
const { measurement, isConsumed } = event;
|
||||
if (!measurement || isConsumed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { unsubscribe } = measurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
|
||||
props => {
|
||||
cacheJumpToMeasurementEvent = props;
|
||||
const { viewportId: jumpId, measurement, isConsumed } = props;
|
||||
if (!measurement || isConsumed) {
|
||||
return;
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport === undefined) {
|
||||
// Decide on which viewport should handle this
|
||||
cacheJumpToMeasurementEvent.cornerstoneViewport =
|
||||
cornerstoneViewportService.getViewportIdToJump(jumpId, {
|
||||
displaySetInstanceUID: measurement.displaySetInstanceUID,
|
||||
...measurement.metadata,
|
||||
referencedImageId:
|
||||
measurement.referencedImageId || measurement.metadata?.referencedImageId,
|
||||
});
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
|
||||
return;
|
||||
}
|
||||
_jumpToMeasurement(measurement, elementRef, viewportId, servicesManager);
|
||||
}
|
||||
const enabledElement = getEnabledElement(elementRef.current);
|
||||
|
||||
if (!enabledElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = enabledElement.viewport as csTypes.IStackViewport | csTypes.IVolumeViewport;
|
||||
|
||||
const { metadata, displaySetInstanceUID } = measurement;
|
||||
|
||||
const viewportDisplaySets = cornerstoneViewportService.getViewportDisplaySets(viewportId);
|
||||
|
||||
const showingDisplaySet = viewportDisplaySets.find(
|
||||
ds => ds.displaySetInstanceUID === displaySetInstanceUID
|
||||
);
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
let metadataToUse = metadata;
|
||||
// if it is not showing the displaySet we need to remove the FOR from the metadata
|
||||
if (!showingDisplaySet) {
|
||||
metadataToUse = {
|
||||
...metadata,
|
||||
FrameOfReferenceUID: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// Check if there is a queued jumpToMeasurement event
|
||||
function _checkForCachedJumpToMeasurementEvents(
|
||||
elementRef,
|
||||
viewportId,
|
||||
displaySets,
|
||||
servicesManager
|
||||
) {
|
||||
if (!cacheJumpToMeasurementEvent) {
|
||||
return;
|
||||
}
|
||||
if (cacheJumpToMeasurementEvent.isConsumed) {
|
||||
cacheJumpToMeasurementEvent = null;
|
||||
return;
|
||||
}
|
||||
const displaysUIDs = displaySets.map(displaySet => displaySet.displaySetInstanceUID);
|
||||
if (!displaysUIDs?.length) {
|
||||
// Todo: make it work with cases where we want to define FOR based measurements too
|
||||
if (!viewport.isReferenceViewable(metadataToUse, WITH_NAVIGATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Jump to measurement if the measurement exists
|
||||
const { measurement } = cacheJumpToMeasurementEvent;
|
||||
if (measurement && elementRef) {
|
||||
if (displaysUIDs.includes(measurement?.displaySetInstanceUID)) {
|
||||
_jumpToMeasurement(measurement, elementRef, viewportId, servicesManager);
|
||||
}
|
||||
try {
|
||||
viewport.setViewReference(metadata);
|
||||
viewport.render();
|
||||
} catch (e) {
|
||||
console.warn('Unable to apply', metadata, e);
|
||||
}
|
||||
}
|
||||
|
||||
function _jumpToMeasurement(measurement, targetElementRef, viewportId, servicesManager) {
|
||||
const { viewportGridService } = servicesManager.services;
|
||||
|
||||
const targetElement = targetElementRef.current;
|
||||
|
||||
// Todo: setCornerstoneMeasurementActive should be handled by the toolGroupManager
|
||||
// to set it properly
|
||||
// setCornerstoneMeasurementActive(measurement);
|
||||
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
|
||||
const enabledElement = getEnabledElement(targetElement);
|
||||
|
||||
if (enabledElement) {
|
||||
// See how the jumpToSlice() of Cornerstone3D deals with imageIdx param.
|
||||
const viewport = enabledElement.viewport as csTypes.IStackViewport | csTypes.IVolumeViewport;
|
||||
|
||||
const { metadata } = measurement;
|
||||
if (!viewport.isReferenceViewable(metadata, WITH_NAVIGATION)) {
|
||||
console.log("Reference isn't viewable, postponing until updated");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
viewport.setViewReference(metadata);
|
||||
} catch (e) {
|
||||
console.warn('Unable to apply', metadata, e);
|
||||
}
|
||||
|
||||
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
|
||||
// Jump to measurement consumed, remove.
|
||||
cacheJumpToMeasurementEvent?.consume?.();
|
||||
cacheJumpToMeasurementEvent = null;
|
||||
}
|
||||
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
|
||||
event?.consume?.();
|
||||
}
|
||||
|
||||
function _rehydrateSynchronizers(viewportId: string, syncGroupService: any) {
|
||||
|
||||
@ -215,6 +215,7 @@ function commandsModule({
|
||||
viewportId,
|
||||
displaySetInstanceUID,
|
||||
referencedImageId,
|
||||
options,
|
||||
}) => {
|
||||
const presentations = cornerstoneViewportService.getPresentations(viewportId);
|
||||
const { positionPresentationStore, setPositionPresentation, getPositionPresentationId } =
|
||||
@ -226,16 +227,18 @@ function commandsModule({
|
||||
([key, value]) => key.includes(displaySetInstanceUID) && value.viewportId === viewportId
|
||||
)?.[0];
|
||||
|
||||
if (previousReferencedDisplaySetStoreKey) {
|
||||
const presentationData = referencedImageId
|
||||
? {
|
||||
...presentations.positionPresentation,
|
||||
viewReference: {
|
||||
referencedImageId,
|
||||
},
|
||||
}
|
||||
: presentations.positionPresentation;
|
||||
// Create presentation data with referencedImageId and options if provided
|
||||
const presentationData = referencedImageId
|
||||
? {
|
||||
...presentations.positionPresentation,
|
||||
viewReference: {
|
||||
referencedImageId,
|
||||
...options,
|
||||
},
|
||||
}
|
||||
: presentations.positionPresentation;
|
||||
|
||||
if (previousReferencedDisplaySetStoreKey) {
|
||||
setPositionPresentation(previousReferencedDisplaySetStoreKey, presentationData);
|
||||
return;
|
||||
}
|
||||
@ -243,13 +246,12 @@ function commandsModule({
|
||||
// if not found means we have not visited that referencedDisplaySetInstanceUID before
|
||||
// so we need to grab the positionPresentationId directly from the store,
|
||||
// Todo: this is really hacky, we should have a better way for this
|
||||
|
||||
const positionPresentationId = getPositionPresentationId({
|
||||
displaySetInstanceUIDs: [displaySetInstanceUID],
|
||||
viewportId,
|
||||
});
|
||||
|
||||
setPositionPresentation(positionPresentationId, presentations.positionPresentation);
|
||||
setPositionPresentation(positionPresentationId, presentationData);
|
||||
},
|
||||
getNearbyToolData({ nearbyToolData, element, canvasCoordinates }) {
|
||||
return nearbyToolData ?? cstUtils.getAnnotationNearPoint(element, canvasCoordinates);
|
||||
|
||||
@ -173,9 +173,6 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
getHangingProtocolModule,
|
||||
getViewportModule({ servicesManager, commandsManager }) {
|
||||
const ExtendedOHIFCornerstoneViewport = props => {
|
||||
// const onNewImageHandler = jumpData => {
|
||||
// commandsManager.runCommand('jumpToImage', jumpData);
|
||||
// };
|
||||
const { toolbarService } = servicesManager.services;
|
||||
|
||||
return (
|
||||
@ -192,6 +189,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
{
|
||||
name: 'cornerstone',
|
||||
component: ExtendedOHIFCornerstoneViewport,
|
||||
isReferenceViewable: props => utils.isReferenceViewable({ ...props, servicesManager }),
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@ -92,6 +92,7 @@ export default async function init({
|
||||
hangingProtocolService,
|
||||
viewportGridService,
|
||||
segmentationService,
|
||||
measurementService,
|
||||
} = servicesManager.services;
|
||||
|
||||
window.services = servicesManager.services;
|
||||
@ -177,6 +178,17 @@ export default async function init({
|
||||
initCineService(servicesManager);
|
||||
initStudyPrefetcherService(servicesManager);
|
||||
|
||||
[
|
||||
measurementService.EVENTS.JUMP_TO_MEASUREMENT_LAYOUT,
|
||||
measurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
|
||||
].forEach(event => {
|
||||
measurementService.subscribe(event, evt => {
|
||||
const { measurement } = evt;
|
||||
const { uid: annotationUID } = measurement;
|
||||
cornerstoneTools.annotation.selection.setAnnotationSelected(annotationUID, true);
|
||||
});
|
||||
});
|
||||
|
||||
segmentationService.subscribeDebounced(
|
||||
segmentationService.EVENTS.SEGMENTATION_DATA_MODIFIED,
|
||||
async ({ segmentationId }) => {
|
||||
|
||||
@ -38,7 +38,7 @@ const EVENTS = {
|
||||
VIEWPORT_VOLUMES_CHANGED: 'event::cornerstoneViewportService:viewportVolumesChanged',
|
||||
};
|
||||
|
||||
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: true };
|
||||
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: false };
|
||||
|
||||
/**
|
||||
* Handles cornerstone viewport logic including enabling, disabling, and
|
||||
@ -851,14 +851,18 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewport.setProperties(properties, volumeId);
|
||||
});
|
||||
|
||||
viewport.render();
|
||||
|
||||
this.setPresentations(viewport.id, presentations, viewportInfo);
|
||||
|
||||
const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
|
||||
if (!presentations.positionPresentation) {
|
||||
const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
|
||||
|
||||
if (imageIndex !== undefined) {
|
||||
csUtils.jumpToSlice(viewport.element, {
|
||||
imageIndex,
|
||||
});
|
||||
if (imageIndex !== undefined) {
|
||||
csUtils.jumpToSlice(viewport.element, {
|
||||
imageIndex,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
viewport.render();
|
||||
@ -1177,6 +1181,20 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display sets for a given viewport
|
||||
* @param viewportId - The ID of the viewport to get display sets for
|
||||
* @returns Array of display sets for the viewport
|
||||
*/
|
||||
public getViewportDisplaySets(viewportId: string): OhifTypes.DisplaySet[] {
|
||||
const { displaySetService } = this.servicesManager.services;
|
||||
const displaySetInstanceUIDs = this.viewportsDisplaySets.get(viewportId) || [];
|
||||
|
||||
return displaySetInstanceUIDs
|
||||
.map(uid => displaySetService.getDisplaySetByUID(uid))
|
||||
.filter(Boolean);
|
||||
}
|
||||
}
|
||||
|
||||
export default CornerstoneViewportService;
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { handleSegmentChange } from './segmentUtils';
|
||||
import { isReferenceViewable } from './isReferenceViewable';
|
||||
|
||||
const utils = {
|
||||
handleSegmentChange,
|
||||
isReferenceViewable,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
|
||||
98
extensions/cornerstone/src/utils/isReferenceViewable.ts
Normal file
98
extensions/cornerstone/src/utils/isReferenceViewable.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import { Enums } from '@cornerstonejs/core';
|
||||
|
||||
import OrientationAxis = Enums.OrientationAxis;
|
||||
|
||||
export const isReferenceViewable = ({
|
||||
viewportId,
|
||||
reference,
|
||||
viewportOptions,
|
||||
servicesManager,
|
||||
}) => {
|
||||
const { cornerstoneViewportService, displaySetService } = servicesManager.services;
|
||||
|
||||
if (!viewportOptions) {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
// we can make a customization for this to allow
|
||||
const isViewable = viewport.isReferenceViewable(reference, {
|
||||
withNavigation: true,
|
||||
});
|
||||
|
||||
return isViewable;
|
||||
}
|
||||
|
||||
if (viewportOptions.viewportType === 'stack') {
|
||||
// we only need the viewport to include the referenced imageId
|
||||
const displaySet = displaySetService.getDisplaySetByUID(reference.displaySetInstanceUID);
|
||||
const imageIds = displaySet.instances.map(instance => instance.imageId);
|
||||
return imageIds.includes(reference.referencedImageId);
|
||||
}
|
||||
|
||||
// for the volume viewports, we need to check orientation
|
||||
const { orientation } = viewportOptions;
|
||||
|
||||
// Todo: handle hanging protocols that have acquisition orientation
|
||||
const closestOrientation = getClosestOrientationFromIOP(
|
||||
displaySetService,
|
||||
reference.displaySetInstanceUID
|
||||
);
|
||||
|
||||
return closestOrientation === orientation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the plane (orientation) to which the ImageOrientationPatient is most closely aligned
|
||||
*
|
||||
* @param displaySetService
|
||||
* @param displaySetInstanceUID
|
||||
* @returns orientation
|
||||
*/
|
||||
export default function getClosestOrientationFromIOP(
|
||||
displaySetService,
|
||||
displaySetInstanceUID
|
||||
): OrientationAxis {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
const imageOrientationPatient = displaySet.instances[0].ImageOrientationPatient as Array<number>;
|
||||
// ImageOrientationPatient must be an array of length 6.
|
||||
if (imageOrientationPatient?.length !== 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Take cross product to get vector coming "out" of image plane
|
||||
const rowCosineVec = vec3.fromValues(
|
||||
imageOrientationPatient[0],
|
||||
imageOrientationPatient[1],
|
||||
imageOrientationPatient[2]
|
||||
);
|
||||
const colCosineVec = vec3.fromValues(
|
||||
imageOrientationPatient[3],
|
||||
imageOrientationPatient[4],
|
||||
imageOrientationPatient[5]
|
||||
);
|
||||
const scanAxisNormal = vec3.cross(vec3.create(), rowCosineVec, colCosineVec);
|
||||
|
||||
// Define the reference vectors for axial, coronal, and sagittal planes
|
||||
const unitVectors = {
|
||||
[OrientationAxis.AXIAL]: vec3.fromValues(0, 0, 1),
|
||||
[OrientationAxis.CORONAL]: vec3.fromValues(0, 1, 0),
|
||||
[OrientationAxis.SAGITTAL]: vec3.fromValues(1, 0, 0),
|
||||
};
|
||||
|
||||
// Compute dot products for each reference plane
|
||||
// Because all vectors are normalized, dot product is bounded between -1 and 1
|
||||
let maxDot = 0;
|
||||
let maxOrientation: string = '';
|
||||
for (const [k, v] of Object.entries(unitVectors)) {
|
||||
// Absolute value of dot product because we only care about alignment with the axis
|
||||
// For example, dot product of -1 for a given axis means perfect alignment
|
||||
// but the image is pointing in the "opposite" direction
|
||||
const res = Math.abs(vec3.dot(scanAxisNormal, v));
|
||||
if (res > maxDot) {
|
||||
maxDot = res;
|
||||
maxOrientation = k;
|
||||
}
|
||||
}
|
||||
|
||||
return maxOrientation as OrientationAxis;
|
||||
}
|
||||
@ -82,7 +82,7 @@ function ViewerLayout({
|
||||
);
|
||||
}
|
||||
|
||||
return { entry, content: entry.component };
|
||||
return { entry };
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -107,6 +107,7 @@ function ViewerLayout({
|
||||
|
||||
return {
|
||||
component: entry.component,
|
||||
isReferenceViewable: entry.isReferenceViewable,
|
||||
displaySetsToDisplay: viewportComponent.displaySetsToDisplay,
|
||||
};
|
||||
};
|
||||
|
||||
@ -14,6 +14,7 @@ const getViewportModule = ({
|
||||
{
|
||||
name: 'chartViewport',
|
||||
component: LineChartViewport,
|
||||
isReferenceViewable: () => false,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "^3.7.16",
|
||||
"@cornerstonejs/tools": "^3.7.16",
|
||||
"@cornerstonejs/core": "^3.7.17",
|
||||
"@cornerstonejs/tools": "^3.7.17",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.140",
|
||||
"@ohif/extension-default": "3.10.0-beta.140",
|
||||
|
||||
@ -268,12 +268,20 @@ function TrackedMeasurementsContextProvider(
|
||||
displaySet.SOPClassHandlerId === SR_SOPCLASSHANDLERID &&
|
||||
displaySet.isRehydratable === true
|
||||
) {
|
||||
console.log('sending event...', trackedMeasurements);
|
||||
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', {
|
||||
const params = {
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
SeriesInstanceUID: displaySet.SeriesInstanceUID,
|
||||
viewportId: activeViewportId,
|
||||
});
|
||||
};
|
||||
|
||||
// Check if we should bypass the confirmation prompt
|
||||
const disableConfirmationPrompts = appConfig?.disableConfirmationPrompts;
|
||||
|
||||
if (disableConfirmationPrompts) {
|
||||
sendTrackedMeasurementsEvent('HYDRATE_SR', params);
|
||||
} else {
|
||||
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', params);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -284,6 +292,7 @@ function TrackedMeasurementsContextProvider(
|
||||
sendTrackedMeasurementsEvent,
|
||||
servicesManager.services,
|
||||
viewports,
|
||||
appConfig,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -57,7 +57,6 @@ const machineConfiguration = {
|
||||
actions: ['setPreviousState'],
|
||||
},
|
||||
],
|
||||
// Unused? We may only do PROMPT_HYDRATE_SR now?
|
||||
SET_TRACKED_SERIES: [
|
||||
{
|
||||
target: 'tracking',
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { utils } from '@ohif/extension-cornerstone';
|
||||
|
||||
const Component = React.lazy(() => {
|
||||
return import(/* webpackPrefetch: true */ './viewports/TrackedCornerstoneViewport');
|
||||
@ -28,6 +29,7 @@ function getViewportModule({ servicesManager, commandsManager, extensionManager
|
||||
{
|
||||
name: 'cornerstone-tracked',
|
||||
component: ExtendedOHIFCornerstoneTrackingViewport,
|
||||
isReferenceViewable: props => utils.isReferenceViewable({ ...props, servicesManager }),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@emotion/serialize": "^1.1.3",
|
||||
"@ohif/core": "3.10.0-beta.140",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.140",
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import React, { useEffect, useCallback, useRef } from 'react';
|
||||
import React, { useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useResizeDetector } from 'react-resize-detector';
|
||||
import { Types, MeasurementService } from '@ohif/core';
|
||||
import { ViewportGrid, ViewportPane } from '@ohif/ui-next';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import EmptyViewport from './EmptyViewport';
|
||||
import classNames from 'classnames';
|
||||
import { useAppConfig } from '@state';
|
||||
|
||||
function ViewerViewportGrid(props: withAppTypes) {
|
||||
const { servicesManager, viewportComponents = [], dataSource } = props;
|
||||
const { servicesManager, viewportComponents = [], dataSource, commandsManager } = props;
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
@ -167,17 +166,51 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = measurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_LAYOUT,
|
||||
({ viewportId, measurement, isConsumed }) => {
|
||||
event => {
|
||||
const { viewportId, measurement, isConsumed } = event;
|
||||
if (isConsumed) {
|
||||
return;
|
||||
}
|
||||
// This occurs when no viewport has elected to consume the event
|
||||
// so we need to change layouts into a layout which can consume
|
||||
// the event.
|
||||
const { displaySetInstanceUID: referencedDisplaySetInstanceUID } = measurement;
|
||||
|
||||
const { displaySetInstanceUID: referencedDisplaySetInstanceUID } = measurement;
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
// Check if any viewport can display this measurement
|
||||
let canAnyViewportDisplayMeasurement = false;
|
||||
|
||||
viewports.forEach((viewport, id) => {
|
||||
const displaySetInstanceUIDs = viewport.displaySetInstanceUIDs || [];
|
||||
const viewportHasDisplaySet = displaySetInstanceUIDs.includes(
|
||||
referencedDisplaySetInstanceUID
|
||||
);
|
||||
|
||||
// Extract metadata and prepare reference
|
||||
const { FrameOfReferenceUID, ...metadataRest } = measurement.metadata;
|
||||
const reference = {
|
||||
...(viewportHasDisplaySet ? measurement.metadata : metadataRest),
|
||||
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
||||
};
|
||||
|
||||
// Check if viewport can display the reference
|
||||
if (
|
||||
viewport.isReferenceViewable?.({
|
||||
viewportId: id,
|
||||
reference,
|
||||
})
|
||||
) {
|
||||
canAnyViewportDisplayMeasurement = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (canAnyViewportDisplayMeasurement) {
|
||||
// Let the viewports handle the jump
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to change layouts since no viewport consumed the event
|
||||
const updatedViewports = _getUpdatedViewports(viewportId, referencedDisplaySetInstanceUID);
|
||||
if (!updatedViewports[0]) {
|
||||
|
||||
if (!updatedViewports?.[0]) {
|
||||
console.warn(
|
||||
'ViewportGrid::Unable to navigate to viewport containing',
|
||||
referencedDisplaySetInstanceUID
|
||||
@ -185,24 +218,35 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Arbitrarily assign the viewport to element 0
|
||||
// TODO - this should perform a search to find the most suitable viewport.
|
||||
updatedViewports[0] = { ...updatedViewports[0] };
|
||||
const [viewport] = updatedViewports;
|
||||
// Find the viewport that can display the measurement
|
||||
const viewport = updatedViewports.find(viewport => {
|
||||
const gridViewport = viewportGridService.getViewportState(viewport.viewportId);
|
||||
return gridViewport.isReferenceViewable?.({
|
||||
viewportId: viewport.viewportId,
|
||||
reference: {
|
||||
...measurement.metadata,
|
||||
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
||||
},
|
||||
viewportOptions: gridViewport.viewportOptions || {},
|
||||
});
|
||||
});
|
||||
|
||||
// Copy the viewport options to prevent modifying the internal data
|
||||
viewport.viewportOptions = {
|
||||
...viewport.viewportOptions,
|
||||
orientation: 'acquisition',
|
||||
// The preferred way to jump to the measurement view is to set the
|
||||
// view reference, as this can hold information such as the orientation
|
||||
// or zoom level required to display an annotation. The metadata attribute
|
||||
// of the measurement is a viewReference, so use it to show the measurement.
|
||||
// Longer term this should clear the view reference data
|
||||
viewReference: measurement.metadata,
|
||||
viewportType: measurement.metadata.volumeId ? 'volume' : null,
|
||||
};
|
||||
if (!viewport) {
|
||||
console.warn('No suitable viewport found for displaying measurement');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update stored position presentation
|
||||
commandsManager.run('updateStoredPositionPresentation', {
|
||||
viewportId: viewport.viewportId,
|
||||
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
||||
referencedImageId: measurement.referencedImageId,
|
||||
options: {
|
||||
...measurement.metadata,
|
||||
},
|
||||
});
|
||||
|
||||
event.consume();
|
||||
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
||||
}
|
||||
);
|
||||
@ -210,7 +254,7 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [viewports]);
|
||||
}, [viewports, _getUpdatedViewports]);
|
||||
|
||||
const onDropHandler = (viewportId, { displaySetInstanceUID }) => {
|
||||
const customOnDropHandler = customizationService.getCustomization('customOnDropHandler');
|
||||
@ -229,6 +273,9 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
});
|
||||
};
|
||||
|
||||
// Store previous isReferenceViewable values to avoid infinite loops
|
||||
const prevReferenceViewableMap = useRef(new Map());
|
||||
|
||||
const getViewportPanes = useCallback(() => {
|
||||
const viewportPanes = [];
|
||||
|
||||
@ -260,12 +307,27 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
return !displaySet?.unsupported;
|
||||
});
|
||||
|
||||
const ViewportComponent = _getViewportComponent(
|
||||
const { component: ViewportComponent, isReferenceViewable } = _getViewportComponent(
|
||||
displaySets,
|
||||
viewportComponents,
|
||||
uiNotificationService
|
||||
);
|
||||
|
||||
// Only update isReferenceViewable if it's changed to avoid render loops
|
||||
// We need to handle both function and non-function values
|
||||
if (viewportId) {
|
||||
const prevValue = prevReferenceViewableMap.current.get(viewportId);
|
||||
const isFunction = typeof isReferenceViewable === 'function';
|
||||
const isSameFunction = isFunction && typeof prevValue === 'function';
|
||||
|
||||
// For non-functions, compare directly. For functions, we treat them as always different
|
||||
// (this is conservative but safe)
|
||||
if (!isSameFunction && prevValue !== isReferenceViewable) {
|
||||
viewportGridService.setIsReferenceViewable(viewportId, isReferenceViewable);
|
||||
prevReferenceViewableMap.current.set(viewportId, isReferenceViewable);
|
||||
}
|
||||
}
|
||||
|
||||
// look inside displaySets to see if they need reRendering
|
||||
const displaySetsNeedsRerendering = displaySets.some(displaySet => {
|
||||
return displaySet.needsRerendering;
|
||||
@ -381,7 +443,7 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
|
||||
function _getViewportComponent(displaySets, viewportComponents, uiNotificationService) {
|
||||
if (!displaySets || !displaySets.length) {
|
||||
return EmptyViewport;
|
||||
return { component: EmptyViewport, isReferenceViewable: () => false };
|
||||
}
|
||||
|
||||
// Todo: Do we have a viewport that has two different SOPClassHandlerIds?
|
||||
@ -395,8 +457,8 @@ function _getViewportComponent(displaySets, viewportComponents, uiNotificationSe
|
||||
throw new Error('displaySetsToDisplay is null');
|
||||
}
|
||||
if (viewportComponents[i].displaySetsToDisplay.includes(SOPClassHandlerId)) {
|
||||
const { component } = viewportComponents[i];
|
||||
return component;
|
||||
const { component, isReferenceViewable } = viewportComponents[i];
|
||||
return { component, isReferenceViewable };
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,7 +469,7 @@ function _getViewportComponent(displaySets, viewportComponents, uiNotificationSe
|
||||
type: 'error',
|
||||
});
|
||||
|
||||
return EmptyViewport;
|
||||
return { component: EmptyViewport, isReferenceViewable: () => false };
|
||||
}
|
||||
|
||||
export default ViewerViewportGrid;
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.16",
|
||||
"@cornerstonejs/dicom-image-loader": "^3.7.17",
|
||||
"@ohif/ui": "3.10.0-beta.140",
|
||||
"cornerstone-math": "0.1.9",
|
||||
"dicom-parser": "^1.8.21"
|
||||
|
||||
@ -670,8 +670,11 @@ class MeasurementService extends PubSubService {
|
||||
measurement,
|
||||
});
|
||||
|
||||
this._broadcastEvent(EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT, consumableEvent);
|
||||
// Important: we should broadcast the layout event first, since
|
||||
// in the layout there might be a viewport that we can match and choose
|
||||
// and jump in it before we decide on changing the orientation of different viewports
|
||||
this._broadcastEvent(EVENTS.JUMP_TO_MEASUREMENT_LAYOUT, consumableEvent);
|
||||
this._broadcastEvent(EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT, consumableEvent);
|
||||
}
|
||||
|
||||
_getSourceUID(name, version) {
|
||||
|
||||
@ -38,6 +38,10 @@ class ViewportGridService extends PubSubService {
|
||||
this.presentationIdProviders.set(id, provider);
|
||||
}
|
||||
|
||||
public setIsReferenceViewable(viewportId: string, isReferenceViewable: boolean): void {
|
||||
this.serviceImplementation._setIsReferenceViewable(viewportId, isReferenceViewable);
|
||||
}
|
||||
|
||||
public getPresentationId(id: string, viewportId: string): string | null {
|
||||
const state = this.getState();
|
||||
const viewport = state.viewports.get(viewportId);
|
||||
@ -93,7 +97,12 @@ class ViewportGridService extends PubSubService {
|
||||
set: setImplementation,
|
||||
getNumViewportPanes: getNumViewportPanesImplementation,
|
||||
setViewportIsReady: setViewportIsReadyImplementation,
|
||||
setIsReferenceViewable: setIsReferenceViewableImplementation,
|
||||
getViewportState: getViewportStateImplementation,
|
||||
}): void {
|
||||
if (getViewportStateImplementation) {
|
||||
this.serviceImplementation._getViewportState = getViewportStateImplementation;
|
||||
}
|
||||
if (getStateImplementation) {
|
||||
this.serviceImplementation._getState = getStateImplementation;
|
||||
}
|
||||
@ -123,6 +132,9 @@ class ViewportGridService extends PubSubService {
|
||||
if (setViewportIsReadyImplementation) {
|
||||
this.serviceImplementation._setViewportIsReady = setViewportIsReadyImplementation;
|
||||
}
|
||||
if (setIsReferenceViewableImplementation) {
|
||||
this.serviceImplementation._setIsReferenceViewable = setIsReferenceViewableImplementation;
|
||||
}
|
||||
}
|
||||
|
||||
public publishViewportsReady() {
|
||||
@ -148,8 +160,7 @@ class ViewportGridService extends PubSubService {
|
||||
}
|
||||
|
||||
public getViewportState(viewportId: string) {
|
||||
const state = this.getState();
|
||||
return state.viewports.get(viewportId);
|
||||
return this.serviceImplementation._getViewportState(viewportId);
|
||||
}
|
||||
|
||||
public setViewportIsReady(viewportId, callback) {
|
||||
|
||||
@ -45,6 +45,10 @@ export interface ViewportGridState {
|
||||
activeViewportId: string | null;
|
||||
layout: Layout;
|
||||
isHangingProtocolLayout: boolean;
|
||||
isReferenceViewable: (props: {
|
||||
viewportId: string;
|
||||
reference: Record<string, unknown>;
|
||||
}) => boolean;
|
||||
viewports: GridViewports;
|
||||
}
|
||||
|
||||
|
||||
54
platform/core/src/utils/getClosestOrientationFromIOP.ts
Normal file
54
platform/core/src/utils/getClosestOrientationFromIOP.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { vec3 } from 'gl-matrix';
|
||||
|
||||
/**
|
||||
* Get the plane (orientation) to which the ImageOrientationPatient is most closely aligned
|
||||
*
|
||||
* @param displaySetService
|
||||
* @param displaySetInstanceUID
|
||||
* @returns orientation
|
||||
*/
|
||||
export default function getClosestOrientationFromIOP(displaySetService, displaySetInstanceUID) {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
const imageOrientationPatient = displaySet.instances[0].ImageOrientationPatient as Array<number>;
|
||||
// ImageOrientationPatient must be an array of length 6.
|
||||
if (imageOrientationPatient?.length !== 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Take cross product to get vector coming "out" of image plane
|
||||
const rowCosineVec = vec3.fromValues(
|
||||
imageOrientationPatient[0],
|
||||
imageOrientationPatient[1],
|
||||
imageOrientationPatient[2]
|
||||
);
|
||||
const colCosineVec = vec3.fromValues(
|
||||
imageOrientationPatient[3],
|
||||
imageOrientationPatient[4],
|
||||
imageOrientationPatient[5]
|
||||
);
|
||||
const scanAxisNormal = vec3.cross(vec3.create(), rowCosineVec, colCosineVec);
|
||||
|
||||
// Define the reference vectors for axial, coronal, and sagittal planes
|
||||
const unitVectors = {
|
||||
axial: vec3.fromValues(0, 0, 1),
|
||||
coronal: vec3.fromValues(0, 1, 0),
|
||||
sagittal: vec3.fromValues(1, 0, 0),
|
||||
};
|
||||
|
||||
// Compute dot products for each reference plane
|
||||
// Because all vectors are normalized, dot product is bounded between -1 and 1
|
||||
let maxDot = 0;
|
||||
let maxOrientation: string = '';
|
||||
for (const [k, v] of Object.entries(unitVectors)) {
|
||||
// Absolute value of dot product because we only care about alignment with the axis
|
||||
// For example, dot product of -1 for a given axis means perfect alignment
|
||||
// but the image is pointing in the "opposite" direction
|
||||
const res = Math.abs(vec3.dot(scanAxisNormal, v));
|
||||
if (res > maxDot) {
|
||||
maxDot = res;
|
||||
maxOrientation = k;
|
||||
}
|
||||
}
|
||||
|
||||
return maxOrientation;
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
import * as utils from './index';
|
||||
|
||||
describe('Top level exports', () => {
|
||||
test('should export the modules ', () => {
|
||||
const expectedExports = [
|
||||
'guid',
|
||||
'ObjectPath',
|
||||
'absoluteUrl',
|
||||
'seriesSortCriteria',
|
||||
'sortBy',
|
||||
'sortStudy',
|
||||
'sortBySeriesDate',
|
||||
'sortStudyInstances',
|
||||
'sortStudySeries',
|
||||
'sortingCriteria',
|
||||
'splitComma',
|
||||
'getSplitParam',
|
||||
'isLowPriorityModality',
|
||||
'writeScript',
|
||||
'debounce',
|
||||
'downloadCSVReport',
|
||||
'imageIdToURI',
|
||||
'roundNumber',
|
||||
'b64toBlob',
|
||||
'sopClassDictionary',
|
||||
'createStudyBrowserTabs',
|
||||
'formatDate',
|
||||
'formatTime',
|
||||
'formatPN',
|
||||
'generateAcceptHeader',
|
||||
'isEqualWithin',
|
||||
//'loadAndCacheDerivedDisplaySets',
|
||||
'isDisplaySetReconstructable',
|
||||
'isImage',
|
||||
'urlUtil',
|
||||
'makeDeferred',
|
||||
'makeCancelable',
|
||||
'hotkeys',
|
||||
'Queue',
|
||||
'isDicomUid',
|
||||
'resolveObjectPath',
|
||||
'hierarchicalListUtils',
|
||||
'progressTrackingUtils',
|
||||
'uuidv4',
|
||||
'addAccessors',
|
||||
'MeasurementFilters',
|
||||
].sort();
|
||||
|
||||
const exports = Object.keys(utils.default).sort();
|
||||
|
||||
expect(exports).toEqual(expectedExports);
|
||||
});
|
||||
});
|
||||
@ -40,7 +40,7 @@ import { splitComma, getSplitParam } from './splitComma';
|
||||
import { createStudyBrowserTabs } from './createStudyBrowserTabs';
|
||||
import { sopClassDictionary } from './sopClassDictionary';
|
||||
import * as MeasurementFilters from './measurementFilters';
|
||||
|
||||
import getClosestOrientationFromIOP from './getClosestOrientationFromIOP';
|
||||
// Commented out unused functionality.
|
||||
// Need to implement new mechanism for derived displaySets using the displaySetManager.
|
||||
|
||||
@ -86,6 +86,7 @@ const utils = {
|
||||
generateAcceptHeader,
|
||||
createStudyBrowserTabs,
|
||||
MeasurementFilters,
|
||||
getClosestOrientationFromIOP,
|
||||
};
|
||||
|
||||
export {
|
||||
@ -120,6 +121,7 @@ export {
|
||||
generateAcceptHeader,
|
||||
createStudyBrowserTabs,
|
||||
MeasurementFilters,
|
||||
getClosestOrientationFromIOP,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
|
||||
@ -141,6 +141,19 @@ interface ViewportGridProviderProps {
|
||||
export function ViewportGridProvider({ children, service }: ViewportGridProviderProps) {
|
||||
const viewportGridReducer = (state: AppTypes.ViewportGrid.State, action) => {
|
||||
switch (action.type) {
|
||||
case 'SET_IS_REFERENCE_VIEWABLE': {
|
||||
const { viewportId, isReferenceViewable } = action.payload;
|
||||
const viewports = new Map(state.viewports);
|
||||
const viewport = viewports.get(viewportId);
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
viewports.set(viewportId, {
|
||||
...viewport,
|
||||
isReferenceViewable,
|
||||
});
|
||||
return { ...state, viewports };
|
||||
}
|
||||
case 'SET_ACTIVE_VIEWPORT_ID': {
|
||||
return { ...state, ...{ activeViewportId: action.payload } };
|
||||
}
|
||||
@ -378,6 +391,13 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const setIsReferenceViewable = useCallback(
|
||||
(viewportId, isReferenceViewable) => {
|
||||
dispatch({ type: 'SET_IS_REFERENCE_VIEWABLE', payload: { viewportId, isReferenceViewable } });
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const setDisplaySetsForViewports = useCallback(
|
||||
viewports =>
|
||||
dispatch({
|
||||
@ -449,6 +469,14 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const getViewportState = useCallback(
|
||||
viewportId => {
|
||||
const { viewports } = viewportGridState;
|
||||
return viewports.get(viewportId);
|
||||
},
|
||||
[viewportGridState]
|
||||
);
|
||||
|
||||
const getNumViewportPanes = useCallback(() => {
|
||||
const { layout, viewports } = viewportGridState;
|
||||
const { numRows, numCols } = layout;
|
||||
@ -466,12 +494,14 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
getState,
|
||||
setActiveViewportId,
|
||||
setDisplaySetsForViewports,
|
||||
setIsReferenceViewable,
|
||||
setLayout,
|
||||
reset,
|
||||
onModeExit: reset,
|
||||
set,
|
||||
getNumViewportPanes,
|
||||
setViewportIsReady,
|
||||
getViewportState,
|
||||
getGridViewportsReady,
|
||||
});
|
||||
}
|
||||
@ -480,12 +510,14 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
service,
|
||||
setActiveViewportId,
|
||||
setDisplaySetsForViewports,
|
||||
setIsReferenceViewable,
|
||||
setLayout,
|
||||
reset,
|
||||
set,
|
||||
getNumViewportPanes,
|
||||
setViewportIsReady,
|
||||
getGridViewportsReady,
|
||||
getViewportState,
|
||||
]);
|
||||
|
||||
// run many of the calls through the service itself since we want to publish events
|
||||
@ -494,7 +526,10 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
setActiveViewportId: index => service.setActiveViewportId(index),
|
||||
setDisplaySetsForViewport: props => service.setDisplaySetsForViewports([props]),
|
||||
setDisplaySetsForViewports: props => service.setDisplaySetsForViewports(props),
|
||||
setIsReferenceViewable: (viewportId, isReferenceViewable) =>
|
||||
service.setIsReferenceViewable(viewportId, isReferenceViewable),
|
||||
setLayout: layout => service.setLayout(layout),
|
||||
getViewportState: viewportId => service.getViewportState(viewportId),
|
||||
reset: () => service.reset(),
|
||||
set: gridLayoutState => service.setState(gridLayoutState), // run it through the service itself since we want to publish events
|
||||
getNumViewportPanes,
|
||||
|
||||
104
tests/JumpToMeasurementMPR.spec.ts
Normal file
104
tests/JumpToMeasurementMPR.spec.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { test } from '@playwright/test';
|
||||
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095258.1';
|
||||
const mode = 'viewer';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate in MPR correctly', async ({ page }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
|
||||
// get the div that has Body 4.0 Lung I and double click it
|
||||
|
||||
await page.locator(':text("S:7")').first().dblclick();
|
||||
|
||||
await page.evaluate(() => {
|
||||
// Access cornerstone directly from the window object
|
||||
const cornerstone = window.cornerstone;
|
||||
if (!cornerstone) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabledElements = cornerstone.getEnabledElements();
|
||||
if (enabledElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = enabledElements[0].viewport;
|
||||
if (viewport) {
|
||||
viewport.setImageIdIndex(20);
|
||||
viewport.render();
|
||||
}
|
||||
});
|
||||
|
||||
await page.getByTestId('MeasurementTools-split-button-secondary').click();
|
||||
await page.getByTestId('Bidirectional').click();
|
||||
const locator = page.getByTestId('viewport-pane').locator('canvas');
|
||||
|
||||
await simulateClicksOnElement({
|
||||
locator,
|
||||
points: [
|
||||
{
|
||||
x: 405,
|
||||
y: 277,
|
||||
},
|
||||
{
|
||||
x: 515,
|
||||
y: 339,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// wait 2 seconds
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
|
||||
// scroll away
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.initialDraw);
|
||||
|
||||
// use mouse wheel to scroll away
|
||||
await page.mouse.wheel(0, 100);
|
||||
|
||||
// wait 2 seconds
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.scrollAway);
|
||||
|
||||
await page.getByTestId('data-row').first().click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.jumpToMeasurementStack);
|
||||
|
||||
await page.getByTestId('Layout').click();
|
||||
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
|
||||
|
||||
// wait 2 seconds
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// jump in viewport again
|
||||
await page.getByTestId('data-row').first().click();
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.jumpInMPR);
|
||||
|
||||
await page.locator(':text("S:3")').first().dblclick();
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.changeSeriesInMPR);
|
||||
|
||||
await page.getByTestId('data-row').first().click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
page,
|
||||
screenShotPaths.jumpToMeasurementMPR.jumpToMeasurementAfterSeriesChange
|
||||
);
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 236 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
@ -102,6 +102,16 @@ const screenShotPaths = {
|
||||
tmtvRendering: {
|
||||
tmtvDisplayedCorrectly: 'tmtvDisplayedCorrectly.png',
|
||||
},
|
||||
jumpToMeasurementMPR: {
|
||||
initialDraw: 'jumpToMeasurementMPR-initialDraw.png',
|
||||
scrollAway: 'jumpToMeasurementMPR-scrollAway.png',
|
||||
jumpToMeasurementStack: 'jumpToMeasurementMPR-jumpToMeasurementStack.png',
|
||||
goToMPR: 'jumpToMeasurementMPR-goToMPR.png',
|
||||
jumpInMPR: 'jumpToMeasurementMPR-jumpInMPR.png',
|
||||
changeSeriesInMPR: 'jumpToMeasurementMPR-changeSeriesInMPR.png',
|
||||
jumpToMeasurementAfterSeriesChange:
|
||||
'jumpToMeasurementMPR-jumpToMeasurementAfterSeriesChange.png',
|
||||
},
|
||||
};
|
||||
|
||||
export { screenShotPaths };
|
||||
|
||||
48
yarn.lock
48
yarn.lock
@ -1393,10 +1393,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@cornerstonejs/adapters@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.7.16.tgz#4ac66230ffba5b527abf4ba58c8b10ef46643c45"
|
||||
integrity sha512-gMLRTZzhIGOwUT9rufpv4uq5iHTJgg2x6GW++eOi/6bEDY2wOiH2peRM8W1EfAoa3cK+lLLoAqEARlVMJq//tg==
|
||||
"@cornerstonejs/adapters@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.7.17.tgz#7e0a84d4010c4757e58c0d350c5604de865d8c56"
|
||||
integrity sha512-K1tz4y5YRgen+z8Yva5mzO3iwn1UZRoqf0wX8VjU1zszx/F4m19DSNcR9H5BJvlGM09DZjpJ42QXK2o9pIvnTg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs2" "^7.17.8"
|
||||
buffer "^6.0.3"
|
||||
@ -1429,20 +1429,20 @@
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
||||
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
||||
|
||||
"@cornerstonejs/core@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.7.16.tgz#7b4a1ab6a726482ddc380eee15299ec1f9461ad5"
|
||||
integrity sha512-5rc371p1P+hk1rUzpHTByW+7Mp6LyahqWJLJwt/55a4BEiEtbhWyTSAz/XKWcOd5bgq7huAsyHKCmMcWrHx3pg==
|
||||
"@cornerstonejs/core@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.7.17.tgz#4a7986aa8bb7a68fbff597d3906e96e6b6483fc2"
|
||||
integrity sha512-2Z3FqrGJept9k1dmlGeMBPon1MDR/P7CkcTTevpKTlYiT3D7bqQ+Q5xdssLzWRD86et0PkRSJGktBM163WCgGw==
|
||||
dependencies:
|
||||
"@kitware/vtk.js" "32.12.1"
|
||||
comlink "^4.4.1"
|
||||
gl-matrix "^3.4.3"
|
||||
loglevel "^1.9.2"
|
||||
|
||||
"@cornerstonejs/dicom-image-loader@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.7.16.tgz#e0ed7621f81b5a3dd38f3e899ac9b7ba4a2a4ea9"
|
||||
integrity sha512-8O3cd9L54s3AFE3DZUMKOUvuuE9MkYuWZ8NgCPtBE1Qky6d4KNGKdljzwmpj8JJ7y7yGLW1rI0KqQc9DCf4//Q==
|
||||
"@cornerstonejs/dicom-image-loader@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.7.17.tgz#b14ba0cf64ab8a454ac086cd1ed6f2481359d533"
|
||||
integrity sha512-LKHQ7x7S47TtF8M4ZmR4S+afbSsAT+yVMkKD81VU3A8oyuX7hT4+cUO4JlGGck3BxG4FyjgNSGT+T3YxAH1SHw==
|
||||
dependencies:
|
||||
"@cornerstonejs/codec-charls" "^1.2.3"
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
||||
@ -1454,25 +1454,25 @@
|
||||
pako "^2.0.4"
|
||||
uuid "^9.0.0"
|
||||
|
||||
"@cornerstonejs/labelmap-interpolation@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.7.16.tgz#fffda0b2da7cbb21ecfed8e19dd72371e5bc73fb"
|
||||
integrity sha512-zoL7arbPywNxUksKkkorcICpIwAgcpYbBBEFIGXt4gSS7NPC7cRU12PU1mj3Cgy+59nO2QIohoPkv0Kj/AwXmA==
|
||||
"@cornerstonejs/labelmap-interpolation@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.7.17.tgz#fb57706c19c77cbc8192d81d9f2d6e086be637ae"
|
||||
integrity sha512-K8R11wqv4TFljMArbx+4JbMtsINeMandp0mD8zyrj1rWXA+RY49QcNa7ob6KBnV26xJqXMT0VyJ0k/Ow53TiLQ==
|
||||
dependencies:
|
||||
"@itk-wasm/morphological-contour-interpolation" "1.1.0"
|
||||
itk-wasm "1.0.0-b.165"
|
||||
|
||||
"@cornerstonejs/polymorphic-segmentation@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.7.16.tgz#75c6b564178e3057075f46e5fa66a1fff3e2c3d5"
|
||||
integrity sha512-HW7h9xRWRDKmaYpv4KWqSYcFz4M2EbMnYNaP+JgnLRws/1eoVPM5YYTsWgyINOM8fdR9o6tMmtMdjcioEGsZPg==
|
||||
"@cornerstonejs/polymorphic-segmentation@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.7.17.tgz#f6b4f4530996d974d59fff97ec29bd34a7a8cb16"
|
||||
integrity sha512-ZI0643arqYbkrjadDSOsGTO2JS1OUtJkF8qEnjjG8MlxqQ7g6sPnTM/atrYRc9ZFoJxFL4kz7D0gOjcBrarYeQ==
|
||||
dependencies:
|
||||
"@icr/polyseg-wasm" "0.4.0"
|
||||
|
||||
"@cornerstonejs/tools@^3.7.16":
|
||||
version "3.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.7.16.tgz#53fd8b8437a63bcfedcb776d9edb0ad7cac414ab"
|
||||
integrity sha512-hmAAmUiEr8z920btZtkT7jqYgZzQqLT82FijfYZVd591nddR25hb77OXEJ+PPAQbvktwPSUZx0kMBoUuM5VpWw==
|
||||
"@cornerstonejs/tools@^3.7.17":
|
||||
version "3.7.17"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.7.17.tgz#dc758ec14e0016bf76d04f54d3e91bd824ebdc7a"
|
||||
integrity sha512-ZDMboShGzMDkqnzEDE7Y9UTJgHqGkVQt8l6AL5dCyA/IIlWEXXdxVe1weotJxgjMqaPETiwJ5EtN/3D4+tf1Rg==
|
||||
dependencies:
|
||||
"@types/offscreencanvas" "2019.7.3"
|
||||
comlink "^4.4.1"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user