Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b0bb9402f | ||
|
|
9cbf82167e | ||
|
|
7f0cc0f60e | ||
|
|
7d67834159 | ||
|
|
51f9407d93 | ||
|
|
fdb073c216 | ||
|
|
d319d20b0d | ||
|
|
8a977bb70c | ||
|
|
9233143b9d | ||
|
|
1f5c60bbda | ||
|
|
ca22bac851 | ||
|
|
32fc6f0d4b | ||
|
|
e2491daff7 | ||
|
|
7dd0260f86 | ||
|
|
4b63d48518 | ||
|
|
4ecffe89cb | ||
|
|
9fb3653281 | ||
|
|
06660be7c4 | ||
|
|
5d5eafb0f5 | ||
|
|
0abb62167a | ||
|
|
3e6913b097 | ||
|
|
4559d39a91 | ||
|
|
b7ddbccdff | ||
|
|
e480e841bb | ||
|
|
afd528b8d7 | ||
|
|
76da2d86a9 | ||
|
|
5527c0e8ea | ||
|
|
bda98b0bee | ||
|
|
74d96d378d | ||
|
|
94496f72b9 | ||
|
|
338e386948 | ||
|
|
0531bee83b | ||
|
|
6411488cd1 | ||
|
|
55f0b54db1 | ||
|
|
2e70f0ffa1 | ||
|
|
0931356f68 | ||
|
|
b7cd0c6027 | ||
|
|
8d83c117cf | ||
|
|
bd93a6f428 | ||
|
|
125f11fc73 | ||
|
|
ce3bc8962d | ||
|
|
0d8820d941 | ||
|
|
c61dbba8d0 | ||
|
|
2410c6a509 | ||
|
|
d26c9551b6 | ||
|
|
b6afba12a5 | ||
|
|
4e16099ad3 | ||
|
|
887a892a5b | ||
|
|
db4d94c3fe | ||
|
|
0b5836ca1a | ||
|
|
8b969eb1e9 | ||
|
|
ac30be6038 | ||
|
|
d8a6e79df0 | ||
|
|
5712e91ca1 | ||
|
|
a3b1251386 | ||
|
|
2fbaa11cf1 | ||
|
|
8fe7b78e54 | ||
|
|
d9a3ba7990 | ||
|
|
2ca9f2b0cc | ||
|
|
559f248d1f | ||
|
|
084a10f783 | ||
|
|
5043ea3260 | ||
|
|
e0ec1011cf | ||
|
|
bbf1a19676 | ||
|
|
9a3d832cc2 | ||
|
|
e373e22481 | ||
|
|
149d6d049c | ||
|
|
4d06a7d286 | ||
|
|
a7e4204cea | ||
|
|
8996df80e4 | ||
|
|
d5dbe20256 | ||
|
|
105fd7a468 | ||
|
|
2c183aa4a7 | ||
|
|
8788dae6a4 | ||
|
|
6937129991 | ||
|
|
8acbd760d8 | ||
|
|
c65e7f57cc | ||
|
|
5e09b405f4 | ||
|
|
12d3db2dbc | ||
|
|
ae9a238289 | ||
|
|
691accacd9 | ||
|
|
e035ef1dcc | ||
|
|
43aa20c372 | ||
|
|
860f76586a | ||
|
|
9b8e5cfd1a | ||
|
|
613401e043 | ||
|
|
47b9a06f74 | ||
|
|
f15eb44b4c | ||
|
|
8f79ebafd9 | ||
|
|
a3c7c2c3da | ||
|
|
32017d15a4 | ||
|
|
e3967e62f2 | ||
|
|
09f9024728 | ||
|
|
0cb6106d0f | ||
|
|
4dc26ae603 | ||
|
|
9850f92b8a | ||
|
|
f10683c667 | ||
|
|
2bfc790870 | ||
|
|
3f08a76aac | ||
|
|
a8d84443a9 | ||
|
|
ac5ae4a29e | ||
|
|
6d9c701fa9 | ||
|
|
054b262e9c | ||
|
|
3dac0f9e73 | ||
|
|
d62c32c898 | ||
|
|
d554f02f7c | ||
|
|
ff6dd3a152 | ||
|
|
a22818c1f4 | ||
|
|
6abb095b8a |
No files matched your search
@@ -2,7 +2,7 @@ version: 2.1
|
||||
|
||||
orbs:
|
||||
codecov: codecov/codecov@1.0.5
|
||||
cypress: cypress-io/cypress@3.3.1
|
||||
cypress: cypress-io/cypress@3.4.2
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
@@ -341,8 +341,10 @@ jobs:
|
||||
steps:
|
||||
- install_bun
|
||||
- run:
|
||||
name: Install Xvfb
|
||||
command: sudo apt-get update && sudo apt-get install -y xvfb
|
||||
name: Install System Dependencies
|
||||
command: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y xvfb libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6
|
||||
- run:
|
||||
name: Start Xvfb
|
||||
command: Xvfb :99 -screen 0 1920x1080x24 &
|
||||
@@ -351,13 +353,11 @@ jobs:
|
||||
name: Export Display Variable
|
||||
command: export DISPLAY=:99
|
||||
- cypress/install:
|
||||
install-browsers: true
|
||||
install-command: bun install --no-save
|
||||
package-manager: yarn
|
||||
- cypress/run-tests:
|
||||
cypress-command:
|
||||
npx wait-on@latest http://localhost:3000 && cd platform/app && npx cypress run --record
|
||||
--browser chrome --parallel
|
||||
cypress-command: |
|
||||
npx wait-on@latest http://localhost:3000 && cd platform/app && npx cypress run --record --parallel
|
||||
start-command: bun run test:data && bun run test:e2e:serve
|
||||
|
||||
DOCKER_MULTIARCH_MANIFEST:
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright:v1.49.0-noble
|
||||
image: mcr.microsoft.com/playwright:v1.50.0-noble
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
+369
@@ -3,6 +3,375 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* separate checks for addWindowLevelActionMenu and addSegmentationOverlay ([#4813](https://github.com/OHIF/Viewers/issues/4813)) ([7f0cc0f](https://github.com/OHIF/Viewers/commit/7f0cc0f60e74a2e0ac2aea1fe6a786582b495c4e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* broken activateViewportBeforeInteraction behavior ([#4810](https://github.com/OHIF/Viewers/issues/4810)) ([fdb073c](https://github.com/OHIF/Viewers/commit/fdb073c216013477c8545db34d254a9ad328fe48))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sr:** sr hydration and load was not working, Screenshot Comparison, and Testing ([#4814](https://github.com/OHIF/Viewers/issues/4814)) ([9233143](https://github.com/OHIF/Viewers/commit/9233143b9da5850080365e1526e24b44e9910075))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hotkeys:** Migrate hotkeys to customization service and fix issues with overrides ([#4777](https://github.com/OHIF/Viewers/issues/4777)) ([3e6913b](https://github.com/OHIF/Viewers/commit/3e6913b097569280a5cc2fa5bbe4add52f149305))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Changes to address hang/crash on jump to instance ([#4679](https://github.com/OHIF/Viewers/issues/4679)) ([e480e84](https://github.com/OHIF/Viewers/commit/e480e841bb5da5281a7c4624a60d5964d690ebb8))
|
||||
* **rt:** jump to segment discards the configured width ([#4799](https://github.com/OHIF/Viewers/issues/4799)) ([afd528b](https://github.com/OHIF/Viewers/commit/afd528b8d72c3d8360b54bb52604758e83ada863))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Delay for all series thumbnails on fetching thumbnail ([#4802](https://github.com/OHIF/Viewers/issues/4802)) ([bda98b0](https://github.com/OHIF/Viewers/commit/bda98b0beebde6294a522b5c7e0ca76724020a2f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* combine frame instance ([#4792](https://github.com/OHIF/Viewers/issues/4792)) ([55f0b54](https://github.com/OHIF/Viewers/commit/55f0b54db1e81a99f9e2d92b1d6d78dfb02762f0))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* icon is not defined ([#4794](https://github.com/OHIF/Viewers/issues/4794)) ([b7cd0c6](https://github.com/OHIF/Viewers/commit/b7cd0c6027debcbfa573bc8068bc2e87928af9a5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** fix for className ([#4604](https://github.com/OHIF/Viewers/issues/4604)) ([125f11f](https://github.com/OHIF/Viewers/commit/125f11fc737f70ec9324798245787f44198e3bd4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cache thumbnail in display set ([#4782](https://github.com/OHIF/Viewers/issues/4782)) ([2410c6a](https://github.com/OHIF/Viewers/commit/2410c6a50904c1235993900e837876cc26af019b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* lodash dependencies ([#4791](https://github.com/OHIF/Viewers/issues/4791)) ([4e16099](https://github.com/OHIF/Viewers/commit/4e16099ad3ab777b09f6ac8f181025cfd656ab6b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* improve dicom tag browser with nested rows ([#4451](https://github.com/OHIF/Viewers/issues/4451)) ([0b5836c](https://github.com/OHIF/Viewers/commit/0b5836ca1a908e152336752672b196f0d533f4f9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* depandabot ([#4786](https://github.com/OHIF/Viewers/issues/4786)) ([d8a6e79](https://github.com/OHIF/Viewers/commit/d8a6e79df008139f7f2f45054b73baf8cd52fb40))
|
||||
* right panel for the create mode cli command ([#4788](https://github.com/OHIF/Viewers/issues/4788)) ([5712e91](https://github.com/OHIF/Viewers/commit/5712e91ca1d939ff3c36615d3cf1a1f6f0051c4f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add viewport overlays to microscopy mode ([#4776](https://github.com/OHIF/Viewers/issues/4776)) ([084a10f](https://github.com/OHIF/Viewers/commit/084a10f7835acab6a851922850c474bc9c7b864b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add commandsManager to MoreDropdownMenu onClick props ([#4765](https://github.com/OHIF/Viewers/issues/4765)) ([bbf1a19](https://github.com/OHIF/Viewers/commit/bbf1a19676b2b345a0f911dde319e5ffefe29fa6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* changing colormap for second volume in fusion viewport ([#4746](https://github.com/OHIF/Viewers/issues/4746)) ([8996df8](https://github.com/OHIF/Viewers/commit/8996df80e45c97ad5847ebbd19291cd772a2163d))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** Add support for Custom Modal component in Modal Service ([#4752](https://github.com/OHIF/Viewers/issues/4752)) ([2c183aa](https://github.com/OHIF/Viewers/commit/2c183aa4a777d7b5a0417ebcc8576a0fc2631ad2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** customization option for viewport notification ([#4638](https://github.com/OHIF/Viewers/issues/4638)) ([8acbd76](https://github.com/OHIF/Viewers/commit/8acbd760d801dcaf624c5d9fb636a029201b91e1))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **context-menu:** Fixing regression introduced by PR [#4727](https://github.com/OHIF/Viewers/issues/4727) ([#4760](https://github.com/OHIF/Viewers/issues/4760)) ([12d3db2](https://github.com/OHIF/Viewers/commit/12d3db2dbc80438df60139c67e9bcf0a610532d6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement label auto-completion:** Customization of measurement label auto-completion fails for measurements following arrow annotations. ([#4739](https://github.com/OHIF/Viewers/issues/4739)) ([e035ef1](https://github.com/OHIF/Viewers/commit/e035ef1dcc72ecbe2a757e3b814551d768d7e610))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **store-segmentation:** storing segmentations was hitting the wrong command resulting in an undefined datasource ([#4755](https://github.com/OHIF/Viewers/issues/4755)) ([9b8e5cf](https://github.com/OHIF/Viewers/commit/9b8e5cfd1a6121a58991c0f75660a2fd9913a4e7))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Remove non-functional Tailwind class for SegmentationPanel ([#4745](https://github.com/OHIF/Viewers/issues/4745)) ([32017d1](https://github.com/OHIF/Viewers/commit/32017d15a4c11e0cb7717c13da022a01ee152ba5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* publish dependency ([#4753](https://github.com/OHIF/Viewers/issues/4753)) ([0cb6106](https://github.com/OHIF/Viewers/commit/0cb6106d0fa576348ca3324685d5768b6ec80572))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* typo in pet_series_module ([#4748](https://github.com/OHIF/Viewers/issues/4748)) ([f10683c](https://github.com/OHIF/Viewers/commit/f10683c667ea8f20c8d3e99ee0fb206522757b71))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **customization:** enable custom onDropHandler for viewportGrid ([#4641](https://github.com/OHIF/Viewers/issues/4641)) ([054b262](https://github.com/OHIF/Viewers/commit/054b262e9cbeb0f44de65d05641efe1e8944a4f5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** Update dcmjs library and improve documentation links ([#4741](https://github.com/OHIF/Viewers/issues/4741)) ([d554f02](https://github.com/OHIF/Viewers/commit/d554f02f7cdb876e4132fb94e3b3df8d11b7bb5c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **side-panels:** Added resize handle interactive feedback for side panels ([#4734](https://github.com/OHIF/Viewers/issues/4734)) ([6abb095](https://github.com/OHIF/Viewers/commit/6abb095b8a39c5ae4f8df8852b3ddb3249ec463f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ Here is a schematic representation of our development workflow:
|
||||
|
||||
### Requirements
|
||||
|
||||
- [Yarn 1.17.3+](https://yarnpkg.com/en/docs/install)
|
||||
- [Yarn 1.20.0+](https://yarnpkg.com/en/docs/install)
|
||||
- [Node 18+](https://nodejs.org/en/)
|
||||
- Yarn Workspaces should be enabled on your machine:
|
||||
- `yarn config set workspaces-experimental true`
|
||||
|
||||
+280
@@ -3,6 +3,286 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/devDependencies
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@externals/devDependencies",
|
||||
"description": "External dev dependencies - put dev build dependencies here",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"engines": {
|
||||
|
||||
@@ -3,6 +3,286 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@externals/dicom-microscopy-viewer",
|
||||
"description": "External reference to dicom-microscopy-viewer",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dicom-microscopy-viewer": "^0.46.1"
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@
|
||||
"resolutions": {
|
||||
"**/@babel/runtime": "^7.20.13",
|
||||
"commander": "8.3.0",
|
||||
"dcmjs": ">=0.33.0",
|
||||
"dcmjs": "0.38.0",
|
||||
"dicomweb-client": ">=0.10.4",
|
||||
"nth-check": "^2.1.1",
|
||||
"trim-newlines": "^5.0.0",
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
5addf51c459cd7371da028d68d8ce8d3e795334d
|
||||
7f0cc0f60e74a2e0ac2aea1fe6a786582b495c4e
|
||||
@@ -3,6 +3,292 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-pmap",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "DICOM Parametric Map read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -33,10 +33,10 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.77",
|
||||
"@ohif/extension-default": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.112",
|
||||
"@ohif/extension-default": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^2.17.2",
|
||||
"@cornerstonejs/core": "^2.17.2",
|
||||
"@cornerstonejs/adapters": "^2.19.14",
|
||||
"@cornerstonejs/core": "^2.19.14",
|
||||
"@kitware/vtk.js": "32.1.1",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { LoadingIndicatorTotalPercent } from '@ohif/ui';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
|
||||
function OHIFCornerstonePMAPViewport(props: withAppTypes) {
|
||||
@@ -13,7 +12,7 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) {
|
||||
extensionManager,
|
||||
} = props;
|
||||
const viewportId = viewportOptions.viewportId;
|
||||
const { displaySetService, segmentationService, uiNotificationService } =
|
||||
const { displaySetService, segmentationService, uiNotificationService, customizationService } =
|
||||
servicesManager.services;
|
||||
|
||||
// PMAP viewport will always have a single display set
|
||||
@@ -21,6 +20,10 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) {
|
||||
throw new Error('PMAP viewport must have a single display set');
|
||||
}
|
||||
|
||||
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
|
||||
'ui.loadingIndicatorTotalPercent'
|
||||
);
|
||||
|
||||
const pmapDisplaySet = displaySets[0];
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const referencedDisplaySetRef = useRef(null);
|
||||
|
||||
@@ -3,6 +3,289 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-rt",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "DICOM RT read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -33,10 +33,10 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.77",
|
||||
"@ohif/extension-default": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.112",
|
||||
"@ohif/extension-default": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { utils } from '@ohif/extension-cornerstone';
|
||||
|
||||
import promptHydrateRT from '../utils/promptHydrateRT';
|
||||
import _getStatusComponent from './_getStatusComponent';
|
||||
@@ -39,12 +40,16 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
|
||||
throw new Error('RT viewport should only have a single display set');
|
||||
}
|
||||
|
||||
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
|
||||
'ui.loadingIndicatorTotalPercent'
|
||||
);
|
||||
|
||||
const rtDisplaySet = displaySets[0];
|
||||
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
|
||||
// States
|
||||
const [selectedSegment, setSelectedSegment] = useState(1);
|
||||
const selectedSegmentObjectIndex: number = 0;
|
||||
const { setPositionPresentation } = usePositionPresentationStore();
|
||||
|
||||
// Hydration means that the RT is opened and segments are loaded into the
|
||||
@@ -137,26 +142,15 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
|
||||
|
||||
const onSegmentChange = useCallback(
|
||||
direction => {
|
||||
const segmentationId = rtDisplaySet.displaySetInstanceUID;
|
||||
const segmentation = segmentationService.getSegmentation(segmentationId);
|
||||
|
||||
const { segments } = segmentation;
|
||||
|
||||
const numberOfSegments = Object.keys(segments).length;
|
||||
|
||||
let newSelectedSegmentIndex = selectedSegment + direction;
|
||||
|
||||
// Segment 0 is always background
|
||||
if (newSelectedSegmentIndex >= numberOfSegments - 1) {
|
||||
newSelectedSegmentIndex = 1;
|
||||
} else if (newSelectedSegmentIndex === 0) {
|
||||
newSelectedSegmentIndex = numberOfSegments - 1;
|
||||
}
|
||||
|
||||
segmentationService.jumpToSegmentCenter(segmentationId, newSelectedSegmentIndex, viewportId);
|
||||
setSelectedSegment(newSelectedSegmentIndex);
|
||||
utils.handleSegmentChange({
|
||||
direction,
|
||||
segDisplaySet: rtDisplaySet,
|
||||
viewportId,
|
||||
selectedSegmentObjectIndex,
|
||||
segmentationService,
|
||||
});
|
||||
},
|
||||
[selectedSegment, segmentationService]
|
||||
[selectedSegmentObjectIndex]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -3,6 +3,295 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cache thumbnail in display set ([#4782](https://github.com/OHIF/Viewers/issues/4782)) ([2410c6a](https://github.com/OHIF/Viewers/commit/2410c6a50904c1235993900e837876cc26af019b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-seg",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "DICOM SEG read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -33,10 +33,10 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.77",
|
||||
"@ohif/extension-default": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.112",
|
||||
"@ohif/extension-default": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^2.17.2",
|
||||
"@cornerstonejs/core": "^2.17.2",
|
||||
"@cornerstonejs/adapters": "^2.19.14",
|
||||
"@cornerstonejs/core": "^2.19.14",
|
||||
"@kitware/vtk.js": "32.1.1",
|
||||
"react-color": "^2.19.3"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
export function getToolbarModule({ servicesManager }: withAppTypes) {
|
||||
const { segmentationService, toolbarService, toolGroupService } = servicesManager.services;
|
||||
return [
|
||||
{
|
||||
name: 'evaluate.cornerstone.hasSegmentation',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const segmentations = segmentationService.getSegmentationRepresentations(viewportId);
|
||||
return {
|
||||
disabled: !segmentations?.length,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.cornerstone.segmentation',
|
||||
evaluate: ({ viewportId, button, toolNames, disabledText }) => {
|
||||
@@ -12,17 +21,23 @@ export function getToolbarModule({ servicesManager }: withAppTypes) {
|
||||
if (!segmentations?.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
className: '!text-common-bright !bg-black opacity-50',
|
||||
disabledText: disabledText ?? 'No segmentations available',
|
||||
};
|
||||
}
|
||||
|
||||
const activeSegmentation = segmentationService.getActiveSegmentation(viewportId);
|
||||
if (!Object.keys(activeSegmentation.segments).length) {
|
||||
return {
|
||||
disabled: true,
|
||||
disabledText: 'Add segment to enable this tool',
|
||||
};
|
||||
}
|
||||
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
|
||||
if (!toolGroup) {
|
||||
return {
|
||||
disabled: true,
|
||||
className: '!text-common-bright ohif-disabled',
|
||||
disabledText: disabledText ?? 'Not available on the current viewport',
|
||||
};
|
||||
}
|
||||
@@ -32,7 +47,6 @@ export function getToolbarModule({ servicesManager }: withAppTypes) {
|
||||
if (!toolGroup.hasTool(toolName) && !toolNames) {
|
||||
return {
|
||||
disabled: true,
|
||||
className: '!text-common-bright ohif-disabled',
|
||||
disabledText: disabledText ?? 'Not available on the current viewport',
|
||||
};
|
||||
}
|
||||
@@ -43,12 +57,6 @@ export function getToolbarModule({ servicesManager }: withAppTypes) {
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
className: isPrimaryActive
|
||||
? '!text-black !bg-primary-light hover:bg-primary-light hover-text-black hover:cursor-pointer'
|
||||
: '!text-common-bright !bg-black hover:bg-primary-light hover:cursor-pointer hover:text-black',
|
||||
// Todo: isActive right now is used for nested buttons where the primary
|
||||
// button needs to be fully rounded (vs partial rounded) when active
|
||||
// otherwise it does not have any other use
|
||||
isActive: isPrimaryActive,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui';
|
||||
import { ViewportActionArrows } from '@ohif/ui';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
|
||||
import promptHydrateSEG from '../utils/promptHydrateSEG';
|
||||
import _getStatusComponent from './_getStatusComponent';
|
||||
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';
|
||||
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
|
||||
import { utils } from '@ohif/extension-cornerstone';
|
||||
|
||||
const SEG_TOOLGROUP_BASE_NAME = 'SEGToolGroup';
|
||||
|
||||
@@ -31,6 +32,10 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
|
||||
viewportActionCornersService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
|
||||
'ui.loadingIndicatorTotalPercent'
|
||||
);
|
||||
|
||||
const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportId}`;
|
||||
|
||||
// SEG viewport will always have a single display set
|
||||
@@ -42,7 +47,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
|
||||
// States
|
||||
const [selectedSegment, setSelectedSegment] = useState(1);
|
||||
let selectedSegmentObjectIndex: number = 0;
|
||||
const { setPositionPresentation } = usePositionPresentationStore();
|
||||
|
||||
// Hydration means that the SEG is opened and segments are loaded into the
|
||||
@@ -127,27 +132,15 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
|
||||
|
||||
const onSegmentChange = useCallback(
|
||||
direction => {
|
||||
const segmentationId = segDisplaySet.displaySetInstanceUID;
|
||||
const segmentation = segmentationService.getSegmentation(segmentationId);
|
||||
|
||||
const { segments } = segmentation;
|
||||
|
||||
const numberOfSegments = Object.keys(segments).length;
|
||||
|
||||
let newSelectedSegmentIndex = selectedSegment + direction;
|
||||
|
||||
// Segment 0 is always background
|
||||
|
||||
if (newSelectedSegmentIndex > numberOfSegments - 1) {
|
||||
newSelectedSegmentIndex = 1;
|
||||
} else if (newSelectedSegmentIndex === 0) {
|
||||
newSelectedSegmentIndex = numberOfSegments - 1;
|
||||
}
|
||||
|
||||
segmentationService.jumpToSegmentCenter(segmentationId, newSelectedSegmentIndex, viewportId);
|
||||
setSelectedSegment(newSelectedSegmentIndex);
|
||||
utils.handleSegmentChange({
|
||||
direction,
|
||||
segDisplaySet: segDisplaySet,
|
||||
viewportId,
|
||||
selectedSegmentObjectIndex,
|
||||
segmentationService,
|
||||
});
|
||||
},
|
||||
[selectedSegment]
|
||||
[selectedSegmentObjectIndex]
|
||||
);
|
||||
|
||||
const hydrateSEG = useCallback(() => {
|
||||
|
||||
@@ -3,6 +3,289 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-sr",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "OHIF extension for an SR Cornerstone Viewport",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -34,10 +34,10 @@
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.77",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.77",
|
||||
"@ohif/ui": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.112",
|
||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.112",
|
||||
"@ohif/ui": "3.10.0-beta.112",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
@@ -46,9 +46,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^2.17.2",
|
||||
"@cornerstonejs/core": "^2.17.2",
|
||||
"@cornerstonejs/tools": "^2.17.2",
|
||||
"@cornerstonejs/adapters": "^2.19.14",
|
||||
"@cornerstonejs/core": "^2.19.14",
|
||||
"@cornerstonejs/tools": "^2.19.14",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,289 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dynamic-volume",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "OHIF extension for 4D volumes data",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -29,11 +29,11 @@
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.77",
|
||||
"@ohif/extension-default": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/ui": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-cornerstone": "3.10.0-beta.112",
|
||||
"@ohif/extension-default": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"@ohif/ui": "3.10.0-beta.112",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/core": "^2.17.2",
|
||||
"@cornerstonejs/tools": "^2.17.2",
|
||||
"@cornerstonejs/core": "^2.19.14",
|
||||
"@cornerstonejs/tools": "^2.19.14",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
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';
|
||||
|
||||
const controlClassNames = {
|
||||
@@ -20,7 +20,10 @@ const Header = ({ title, tooltip }) => (
|
||||
/>
|
||||
</span>
|
||||
</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>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -37,23 +40,16 @@ const DynamicVolumeControls = ({
|
||||
minFps,
|
||||
maxFps,
|
||||
// Frames
|
||||
currentFrameIndex,
|
||||
onFrameChange,
|
||||
framesLength,
|
||||
currentDimensionGroupNumber,
|
||||
onDimensionGroupChange,
|
||||
numDimensionGroups,
|
||||
onGenerate,
|
||||
onDoubleRangeChange,
|
||||
rangeValues,
|
||||
onDynamicClick,
|
||||
}) => {
|
||||
const [computedView, setComputedView] = useState(false);
|
||||
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 (
|
||||
<div className="flex select-none flex-col">
|
||||
@@ -89,7 +85,7 @@ const DynamicVolumeControls = ({
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
<div>
|
||||
<FrameControls
|
||||
<DimensionGroupControls
|
||||
onPlayPauseChange={onPlayPauseChange}
|
||||
isPlaying={isPlaying}
|
||||
computedView={computedView}
|
||||
@@ -99,9 +95,9 @@ const DynamicVolumeControls = ({
|
||||
minFps={minFps}
|
||||
maxFps={maxFps}
|
||||
//
|
||||
framesLength={framesLength}
|
||||
onFrameChange={onFrameChange}
|
||||
currentFrameIndex={currentFrameIndex}
|
||||
numDimensionGroups={numDimensionGroups}
|
||||
onDimensionGroupChange={onDimensionGroupChange}
|
||||
currentDimensionGroupNumber={currentDimensionGroupNumber}
|
||||
/>
|
||||
</div>
|
||||
<div className={`mt-6 flex flex-col ${computedView ? '' : 'ohif-disabled'}`}>
|
||||
@@ -111,9 +107,10 @@ const DynamicVolumeControls = ({
|
||||
<div>
|
||||
Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to be
|
||||
applied to the data set.
|
||||
<br /> Range Slider: Choose the numeric range within which the operation will be
|
||||
performed.
|
||||
<br />Generate Button: Execute the chosen operation on the specified range of data.
|
||||
<br /> Range Slider: Choose the numeric range of dimension groups within which the
|
||||
operation will be performed.
|
||||
<br />
|
||||
Generate Button: Execute the chosen operation on the specified range of data.
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
@@ -141,15 +138,15 @@ const DynamicVolumeControls = ({
|
||||
</button>
|
||||
</ButtonGroup>
|
||||
<div className="mt-2 w-full">
|
||||
<DoubleSlider
|
||||
min={0}
|
||||
max={framesLength - 1}
|
||||
step={1}
|
||||
defaultValue={sliderRangeValues}
|
||||
onValueChange={handleSliderChange}
|
||||
formatLabel={formatLabel}
|
||||
className="w-full"
|
||||
/>
|
||||
<Numeric.Container
|
||||
mode="doubleRange"
|
||||
min={1}
|
||||
max={numDimensionGroups}
|
||||
values={rangeValues}
|
||||
onChange={onDoubleRangeChange}
|
||||
>
|
||||
<Numeric.DoubleRange showNumberInputs />
|
||||
</Numeric.Container>
|
||||
</div>
|
||||
<Button
|
||||
className="mt-2 !h-[26px] !w-[115px] self-start !p-0"
|
||||
@@ -167,16 +164,16 @@ const DynamicVolumeControls = ({
|
||||
|
||||
export default DynamicVolumeControls;
|
||||
|
||||
function FrameControls({
|
||||
function DimensionGroupControls({
|
||||
isPlaying,
|
||||
onPlayPauseChange,
|
||||
fps,
|
||||
minFps,
|
||||
maxFps,
|
||||
onFpsChange,
|
||||
framesLength,
|
||||
onFrameChange,
|
||||
currentFrameIndex,
|
||||
numDimensionGroups,
|
||||
onDimensionGroupChange,
|
||||
currentDimensionGroupNumber,
|
||||
computedView,
|
||||
}) {
|
||||
const getPlayPauseIconName = () => (isPlaying ? 'icon-pause' : 'icon-play');
|
||||
@@ -187,14 +184,16 @@ function FrameControls({
|
||||
title="4D Controls"
|
||||
tooltip={
|
||||
<div>
|
||||
Play/Pause Button: Begin or pause the animation of the 4D visualization. <br /> Frame
|
||||
Selector: Navigate through individual frames of the 4D data. <br /> FPS (Frames Per
|
||||
Second) Selector: Adjust the playback speed of the animation.
|
||||
Play/Pause Button: Begin or pause the animation of the 4D visualization. <br />
|
||||
Dimension Group Selector: Navigate through individual dimension groups of the 4D data.{' '}
|
||||
<br />
|
||||
FPS (Frames Per Second) Selector: Adjust the playback speed of the animation.
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<div className="mt-3 flex justify-between">
|
||||
<IconButton
|
||||
id="play-pause-button"
|
||||
className="bg-customblue-30 h-[26px] w-[58px] rounded-[4px]"
|
||||
onClick={() => onPlayPauseChange(!isPlaying)}
|
||||
>
|
||||
@@ -204,11 +203,11 @@ function FrameControls({
|
||||
/>
|
||||
</IconButton>
|
||||
<InputNumber
|
||||
value={currentFrameIndex}
|
||||
onChange={onFrameChange}
|
||||
minValue={0}
|
||||
maxValue={framesLength - 1}
|
||||
label="Frame"
|
||||
value={currentDimensionGroupNumber}
|
||||
onChange={onDimensionGroupChange}
|
||||
minValue={1}
|
||||
maxValue={numDimensionGroups}
|
||||
label="Group"
|
||||
{...controlClassNames}
|
||||
/>
|
||||
<InputNumber
|
||||
@@ -222,4 +221,4 @@ function FrameControls({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,12 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
const [{ activeViewportId }] = useViewportGrid();
|
||||
|
||||
//
|
||||
const [timePointsRange, setTimePointsRange] = useState([0, 0]);
|
||||
const [timePointsRangeToUseForGenerate, setTimePointsRangeToUseForGenerate] = useState([0, 0]);
|
||||
const [dimensionGroupRange, setDimensionGroupRange] = useState([1, 1]);
|
||||
const [computedDisplaySet, setComputedDisplaySet] = useState(null);
|
||||
const [dynamicVolume, setDynamicVolume] = useState(null);
|
||||
const [frameRate, setFrameRate] = useState(20);
|
||||
const [isPlaying, setIsPlaying] = useState(isCineEnabled);
|
||||
const [timePointRendered, setTimePointRendered] = useState(null);
|
||||
const [dimensionGroupNumberRendered, setDimensionGroupNumberRendered] = useState(null);
|
||||
const [displayingComputed, setDisplayingComputed] = useState(false);
|
||||
|
||||
//
|
||||
@@ -38,9 +37,8 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
if (volumeData.volume?.isDynamicVolume()) {
|
||||
setDynamicVolume(volumeData.volume);
|
||||
uuidDynamicVolume.current = volumeData.displaySetInstanceUID;
|
||||
const newRange = [1, volumeData.volume.numTimePoints];
|
||||
setTimePointsRange(newRange);
|
||||
setTimePointsRangeToUseForGenerate(newRange);
|
||||
const newRange = [1, volumeData.volume.numDimensionGroups];
|
||||
setDimensionGroupRange(newRange);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -65,10 +63,10 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
}, [cornerstoneViewportService, cineService, servicesManager.services.cineService]);
|
||||
|
||||
useEffect(() => {
|
||||
const evt = Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED;
|
||||
const evt = Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED;
|
||||
|
||||
const callback = evt => {
|
||||
setTimePointRendered(evt.detail.timePointIndex);
|
||||
setDimensionGroupNumberRendered(evt.detail.dimensionGroupNumber);
|
||||
};
|
||||
|
||||
eventTarget.addEventListener(evt, callback);
|
||||
@@ -76,7 +74,7 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
return () => {
|
||||
eventTarget.removeEventListener(evt, callback);
|
||||
};
|
||||
}, [cornerstoneViewportService]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId);
|
||||
@@ -102,9 +100,7 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
|
||||
setDynamicVolume(dynamicVolume);
|
||||
uuidDynamicVolume.current = dynamicVolumeDisplaySet.displaySetInstanceUID;
|
||||
const newRange = [1, dynamicVolume.numTimePoints];
|
||||
setTimePointsRange(newRange);
|
||||
setTimePointsRangeToUseForGenerate(newRange);
|
||||
setDimensionGroupRange([1, dynamicVolume.numDimensionGroups]);
|
||||
}, [
|
||||
activeViewportId,
|
||||
viewportGridService,
|
||||
@@ -141,11 +137,12 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
volumeId: computedVolumeId,
|
||||
});
|
||||
}
|
||||
const [start, end] = timePointsRangeToUseForGenerate;
|
||||
const frameNumbers = Array.from({ length: end - start + 1 }, (_, i) => i + start - 1);
|
||||
const [start, end] = dimensionGroupRange;
|
||||
// from start to end, with steps of 1
|
||||
const frameNumbers = Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
||||
|
||||
const options = {
|
||||
frameNumbers: operationName === 'SUBTRACT' ? [start, end - 1] : frameNumbers,
|
||||
dimensionGroupNumbers: operationName === 'SUBTRACT' ? [start, end] : frameNumbers,
|
||||
targetVolume: computedVolume,
|
||||
};
|
||||
|
||||
@@ -207,17 +204,6 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
handlePlay();
|
||||
};
|
||||
|
||||
function handleSliderChange(newValues) {
|
||||
if (
|
||||
newValues[0] === timePointsRangeToUseForGenerate[0] &&
|
||||
newValues[1] === timePointsRangeToUseForGenerate[1]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimePointsRangeToUseForGenerate(newValues);
|
||||
}
|
||||
|
||||
return (
|
||||
<DynamicVolumeControls
|
||||
fps={frameRate}
|
||||
@@ -225,16 +211,16 @@ export default function PanelGenerateImage({ servicesManager, commandsManager }:
|
||||
onPlayPauseChange={onPlayPauseChange}
|
||||
minFps={1}
|
||||
maxFps={50}
|
||||
currentFrameIndex={timePointRendered}
|
||||
onFpsChange={handleSetFrameRate}
|
||||
framesLength={timePointsRange[1]}
|
||||
onFrameChange={timePointIndex => {
|
||||
dynamicVolume.timePointIndex = timePointIndex;
|
||||
currentDimensionGroupNumber={dimensionGroupNumberRendered}
|
||||
numDimensionGroups={dynamicVolume?.numDimensionGroups || 1}
|
||||
onDimensionGroupChange={dimensionGroupNumber => {
|
||||
dynamicVolume.dimensionGroupNumber = dimensionGroupNumber;
|
||||
}}
|
||||
onGenerate={onGenerateImage}
|
||||
onDynamicClick={displayingComputed ? () => renderDynamicImage(computedDisplaySet) : null}
|
||||
onDoubleRangeChange={handleSliderChange}
|
||||
initialRangeValues={timePointsRangeToUseForGenerate}
|
||||
onDoubleRangeChange={setDimensionGroupRange}
|
||||
rangeValues={dimensionGroupRange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,323 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* separate checks for addWindowLevelActionMenu and addSegmentationOverlay ([#4813](https://github.com/OHIF/Viewers/issues/4813)) ([7f0cc0f](https://github.com/OHIF/Viewers/commit/7f0cc0f60e74a2e0ac2aea1fe6a786582b495c4e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sr:** sr hydration and load was not working, Screenshot Comparison, and Testing ([#4814](https://github.com/OHIF/Viewers/issues/4814)) ([9233143](https://github.com/OHIF/Viewers/commit/9233143b9da5850080365e1526e24b44e9910075))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hotkeys:** Migrate hotkeys to customization service and fix issues with overrides ([#4777](https://github.com/OHIF/Viewers/issues/4777)) ([3e6913b](https://github.com/OHIF/Viewers/commit/3e6913b097569280a5cc2fa5bbe4add52f149305))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Changes to address hang/crash on jump to instance ([#4679](https://github.com/OHIF/Viewers/issues/4679)) ([e480e84](https://github.com/OHIF/Viewers/commit/e480e841bb5da5281a7c4624a60d5964d690ebb8))
|
||||
* **rt:** jump to segment discards the configured width ([#4799](https://github.com/OHIF/Viewers/issues/4799)) ([afd528b](https://github.com/OHIF/Viewers/commit/afd528b8d72c3d8360b54bb52604758e83ada863))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cache thumbnail in display set ([#4782](https://github.com/OHIF/Viewers/issues/4782)) ([2410c6a](https://github.com/OHIF/Viewers/commit/2410c6a50904c1235993900e837876cc26af019b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* lodash dependencies ([#4791](https://github.com/OHIF/Viewers/issues/4791)) ([4e16099](https://github.com/OHIF/Viewers/commit/4e16099ad3ab777b09f6ac8f181025cfd656ab6b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* changing colormap for second volume in fusion viewport ([#4746](https://github.com/OHIF/Viewers/issues/4746)) ([8996df8](https://github.com/OHIF/Viewers/commit/8996df80e45c97ad5847ebbd19291cd772a2163d))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** customization option for viewport notification ([#4638](https://github.com/OHIF/Viewers/issues/4638)) ([8acbd76](https://github.com/OHIF/Viewers/commit/8acbd760d801dcaf624c5d9fb636a029201b91e1))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **store-segmentation:** storing segmentations was hitting the wrong command resulting in an undefined datasource ([#4755](https://github.com/OHIF/Viewers/issues/4755)) ([9b8e5cf](https://github.com/OHIF/Viewers/commit/9b8e5cfd1a6121a58991c0f75660a2fd9913a4e7))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* publish dependency ([#4753](https://github.com/OHIF/Viewers/issues/4753)) ([0cb6106](https://github.com/OHIF/Viewers/commit/0cb6106d0fa576348ca3324685d5768b6ec80572))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "OHIF extension for Cornerstone",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -38,10 +38,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": "^2.17.2",
|
||||
"@icr/polyseg-wasm": "^0.4.0",
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/ui": "3.10.0-beta.77",
|
||||
"@cornerstonejs/dicom-image-loader": "^2.19.14",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/ui": "3.10.0-beta.112",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
@@ -50,19 +49,20 @@
|
||||
"react-dom": "^18.3.1",
|
||||
"react-resize-detector": "^10.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/adapters": "^2.17.2",
|
||||
"@cornerstonejs/core": "^2.17.2",
|
||||
"@cornerstonejs/tools": "^2.17.2",
|
||||
"@cornerstonejs/adapters": "^2.19.14",
|
||||
"@cornerstonejs/core": "^2.19.14",
|
||||
"@cornerstonejs/tools": "^2.19.14",
|
||||
"@icr/polyseg-wasm": "^0.4.0",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "32.1.1",
|
||||
"html2canvas": "^1.4.1",
|
||||
"lodash.compact": "^3.0.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.flatten": "^4.4.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"lodash.zip": "^4.2.0",
|
||||
"shader-loader": "^1.3.1",
|
||||
"worker-loader": "^3.0.8"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useResizeDetector } from 'react-resize-detector';
|
||||
import * as cs3DTools from '@cornerstonejs/tools';
|
||||
import { Enums, eventTarget, getEnabledElement } from '@cornerstonejs/core';
|
||||
import { MeasurementService } from '@ohif/core';
|
||||
import { AllInOneMenu, Notification, useViewportDialog } from '@ohif/ui';
|
||||
import { AllInOneMenu, useViewportDialog } from '@ohif/ui';
|
||||
import type { Types as csTypes } from '@cornerstonejs/core';
|
||||
|
||||
import { setEnabledElement } from '../state';
|
||||
@@ -15,11 +15,11 @@ import type { Types } from '@ohif/core';
|
||||
|
||||
import OHIFViewportActionCorners from '../components/OHIFViewportActionCorners';
|
||||
import { getWindowLevelActionMenu } from '../components/WindowLevelActionMenu/getWindowLevelActionMenu';
|
||||
import { useAppConfig } from '@state';
|
||||
import { getViewportDataOverlaySettingsMenu } from '../components/ViewportDataOverlaySettingMenu';
|
||||
import { getViewportPresentations } from '../utils/presentations/getViewportPresentations';
|
||||
import { useSynchronizersStore } from '../stores/useSynchronizersStore';
|
||||
import ActiveViewportBehavior from '../utils/ActiveViewportBehavior';
|
||||
import { WITH_NAVIGATION } from '../services/ViewportService/CornerstoneViewportService';
|
||||
|
||||
const STACK = 'stack';
|
||||
|
||||
@@ -88,7 +88,6 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
||||
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
||||
const elementRef = useRef() as React.MutableRefObject<HTMLDivElement>;
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
const {
|
||||
displaySetService,
|
||||
@@ -99,6 +98,7 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
segmentationService,
|
||||
cornerstoneCacheService,
|
||||
viewportActionCornersService,
|
||||
customizationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const [viewportDialogState] = useViewportDialog();
|
||||
@@ -322,57 +322,60 @@ const OHIFCornerstoneViewport = React.memo(
|
||||
|
||||
// Set up the window level action menu in the viewport action corners.
|
||||
useEffect(() => {
|
||||
// Doing an === check here because the default config value when not set is true
|
||||
if (appConfig.addWindowLevelActionMenu === false) {
|
||||
return;
|
||||
const windowLevelActionMenu = customizationService.getCustomization(
|
||||
'viewportActionMenu.windowLevelActionMenu'
|
||||
);
|
||||
const segmentationOverlay = customizationService.getCustomization(
|
||||
'viewportActionMenu.segmentationOverlay'
|
||||
);
|
||||
|
||||
if (windowLevelActionMenu?.enabled) {
|
||||
viewportActionCornersService.addComponent({
|
||||
viewportId,
|
||||
id: 'windowLevelActionMenu',
|
||||
component: getWindowLevelActionMenu({
|
||||
viewportId,
|
||||
element: elementRef.current,
|
||||
displaySets,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
location: windowLevelActionMenu.location,
|
||||
verticalDirection: AllInOneMenu.VerticalDirection.TopToBottom,
|
||||
horizontalDirection: AllInOneMenu.HorizontalDirection.RightToLeft,
|
||||
}),
|
||||
location: windowLevelActionMenu.location,
|
||||
});
|
||||
}
|
||||
|
||||
const location = viewportActionCornersService.LOCATIONS.topRight;
|
||||
|
||||
// TODO: In the future we should consider using the customization service
|
||||
// to determine if and in which corner various action components should go.
|
||||
viewportActionCornersService.addComponent({
|
||||
viewportId,
|
||||
id: 'windowLevelActionMenu',
|
||||
component: getWindowLevelActionMenu({
|
||||
if (segmentationOverlay?.enabled) {
|
||||
viewportActionCornersService.addComponent({
|
||||
viewportId,
|
||||
element: elementRef.current,
|
||||
displaySets,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
location,
|
||||
verticalDirection: AllInOneMenu.VerticalDirection.TopToBottom,
|
||||
horizontalDirection: AllInOneMenu.HorizontalDirection.RightToLeft,
|
||||
}),
|
||||
location,
|
||||
});
|
||||
|
||||
viewportActionCornersService.addComponent({
|
||||
viewportId,
|
||||
id: 'segmentation',
|
||||
component: getViewportDataOverlaySettingsMenu({
|
||||
viewportId,
|
||||
element: elementRef.current,
|
||||
displaySets,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
location,
|
||||
}),
|
||||
location,
|
||||
});
|
||||
id: 'segmentation',
|
||||
component: getViewportDataOverlaySettingsMenu({
|
||||
viewportId,
|
||||
element: elementRef.current,
|
||||
displaySets,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
location: segmentationOverlay.location,
|
||||
}),
|
||||
location: segmentationOverlay.location,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
displaySets,
|
||||
viewportId,
|
||||
viewportActionCornersService,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
appConfig,
|
||||
]);
|
||||
|
||||
const { ref: resizeRef } = useResizeDetector({
|
||||
onResize,
|
||||
});
|
||||
|
||||
const Notification = customizationService.getCustomization('ui.notificationComponent');
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="viewport-wrapper">
|
||||
@@ -502,12 +505,16 @@ function _jumpToMeasurement(measurement, targetElementRef, viewportId, servicesM
|
||||
const viewport = enabledElement.viewport as csTypes.IStackViewport | csTypes.IVolumeViewport;
|
||||
|
||||
const { metadata } = measurement;
|
||||
if (!viewport.isReferenceViewable(metadata, { withNavigation: true, withOrientation: true })) {
|
||||
if (!viewport.isReferenceViewable(metadata, WITH_NAVIGATION)) {
|
||||
console.log("Reference isn't viewable, postponing until updated");
|
||||
return;
|
||||
}
|
||||
|
||||
viewport.setViewReference(metadata);
|
||||
try {
|
||||
viewport.setViewReference(metadata);
|
||||
} catch (e) {
|
||||
console.warn('Unable to apply', metadata, e);
|
||||
}
|
||||
|
||||
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
|
||||
// Jump to measurement consumed, remove.
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
colorPickerDialog,
|
||||
} from '@ohif/extension-default';
|
||||
import { vec3, mat4 } from 'gl-matrix';
|
||||
|
||||
import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm';
|
||||
import toggleImageSliceSync from './utils/imageSliceSync/toggleImageSliceSync';
|
||||
import { getFirstAnnotationSelected } from './utils/measurementServiceMappings/utils/selection';
|
||||
@@ -34,6 +33,7 @@ import toggleVOISliceSync from './utils/toggleVOISliceSync';
|
||||
import { usePositionPresentationStore, useSegmentationPresentationStore } from './stores';
|
||||
import { toolNames } from './initCornerstoneTools';
|
||||
|
||||
const { DefaultHistoryMemo } = csUtils.HistoryMemo;
|
||||
const toggleSyncFunctions = {
|
||||
imageSlice: toggleImageSliceSync,
|
||||
voi: toggleVOISliceSync,
|
||||
@@ -140,19 +140,16 @@ function commandsModule({
|
||||
)?.[0];
|
||||
|
||||
if (previousReferencedDisplaySetStoreKey) {
|
||||
if (referencedImageId) {
|
||||
setPositionPresentation(previousReferencedDisplaySetStoreKey, {
|
||||
viewReference: {
|
||||
referencedImageId,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
setPositionPresentation(
|
||||
previousReferencedDisplaySetStoreKey,
|
||||
presentations.positionPresentation
|
||||
);
|
||||
}
|
||||
const presentationData = referencedImageId
|
||||
? {
|
||||
...presentations.positionPresentation,
|
||||
viewReference: {
|
||||
referencedImageId,
|
||||
},
|
||||
}
|
||||
: presentations.positionPresentation;
|
||||
|
||||
setPositionPresentation(previousReferencedDisplaySetStoreKey, presentationData);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -208,8 +205,9 @@ function commandsModule({
|
||||
*/
|
||||
setMeasurementLabel: ({ uid }) => {
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
|
||||
(val: Map<any, any>) => {
|
||||
measurementService.update(
|
||||
uid,
|
||||
@@ -325,16 +323,19 @@ function commandsModule({
|
||||
|
||||
renameMeasurement: ({ uid }) => {
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => {
|
||||
measurementService.update(
|
||||
uid,
|
||||
{
|
||||
...val,
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
|
||||
val => {
|
||||
measurementService.update(
|
||||
uid,
|
||||
{
|
||||
...val,
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
toggleLockMeasurement: ({ uid }) => {
|
||||
@@ -376,7 +377,8 @@ function commandsModule({
|
||||
},
|
||||
arrowTextCallback: ({ callback, data, uid }) => {
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig);
|
||||
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
||||
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig, renderContent);
|
||||
},
|
||||
toggleCine: () => {
|
||||
const { viewports } = viewportGridService.getState();
|
||||
@@ -425,6 +427,37 @@ function commandsModule({
|
||||
|
||||
actions.setViewportWindowLevel({ ...props, viewportId });
|
||||
},
|
||||
setWindowLevelPreset: ({ presetName, presetIndex }) => {
|
||||
const windowLevelPresets = customizationService.getCustomization(
|
||||
'cornerstone.windowLevelPresets'
|
||||
);
|
||||
|
||||
const activeViewport = viewportGridService.getActiveViewportId();
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(activeViewport);
|
||||
const metadata = viewport.getImageData().metadata;
|
||||
|
||||
const modality = metadata.Modality;
|
||||
|
||||
if (!modality) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowLevelPresetForModality = windowLevelPresets[modality];
|
||||
|
||||
if (!windowLevelPresetForModality) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowLevelPreset =
|
||||
windowLevelPresetForModality[presetName] ??
|
||||
Object.values(windowLevelPresetForModality)[presetIndex];
|
||||
|
||||
actions.setViewportWindowLevel({
|
||||
viewportId: activeViewport,
|
||||
window: windowLevelPreset.window,
|
||||
level: windowLevelPreset.level,
|
||||
});
|
||||
},
|
||||
setToolEnabled: ({ toolName, toggle, toolGroupId }) => {
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
@@ -751,7 +784,12 @@ function commandsModule({
|
||||
displaySetInstanceUID = viewports.get(viewportId)?.displaySetInstanceUIDs[0];
|
||||
}
|
||||
|
||||
const volumeId = viewport.getVolumeId();
|
||||
// ToDo: Find a better way of obtaining the volumeId that corresponds to the displaySetInstanceUID
|
||||
const volumeId =
|
||||
viewport
|
||||
.getAllVolumeIds()
|
||||
.find((_volumeId: string) => _volumeId.includes(displaySetInstanceUID)) ??
|
||||
viewport.getVolumeId();
|
||||
viewport.setProperties({ colormap }, volumeId);
|
||||
}
|
||||
|
||||
@@ -1317,6 +1355,12 @@ function commandsModule({
|
||||
measurementService.remove(activeAnnotationUID);
|
||||
});
|
||||
},
|
||||
undo: () => {
|
||||
DefaultHistoryMemo.undo();
|
||||
},
|
||||
redo: () => {
|
||||
DefaultHistoryMemo.redo();
|
||||
},
|
||||
};
|
||||
|
||||
const definitions = {
|
||||
@@ -1381,6 +1425,9 @@ function commandsModule({
|
||||
setWindowLevel: {
|
||||
commandFn: actions.setWindowLevel,
|
||||
},
|
||||
setWindowLevelPreset: {
|
||||
commandFn: actions.setWindowLevelPreset,
|
||||
},
|
||||
setToolActive: {
|
||||
commandFn: actions.setToolActive,
|
||||
},
|
||||
@@ -1580,6 +1627,8 @@ function commandsModule({
|
||||
deleteActiveAnnotation: {
|
||||
commandFn: actions.deleteActiveAnnotation,
|
||||
},
|
||||
undo: actions.undo,
|
||||
redo: actions.redo,
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -53,13 +53,13 @@ function WrappedCinePlayer({
|
||||
// check if the displaySet is dynamic and set the dynamic info
|
||||
if (displaySet.isDynamicVolume) {
|
||||
const { dynamicVolumeInfo } = displaySet;
|
||||
const numTimePoints = dynamicVolumeInfo.timePoints.length;
|
||||
const numDimensionGroups = dynamicVolumeInfo.timePoints.length;
|
||||
const label = dynamicVolumeInfo.splittingTag;
|
||||
const timePointIndex = dynamicVolumeInfo.timePointIndex || 0;
|
||||
const dimensionGroupNumber = dynamicVolumeInfo.dimensionGroupNumber || 1;
|
||||
setDynamicInfo({
|
||||
volumeId: displaySet.displaySetInstanceUID,
|
||||
timePointIndex,
|
||||
numTimePoints,
|
||||
dimensionGroupNumber,
|
||||
numDimensionGroups,
|
||||
label,
|
||||
});
|
||||
} else {
|
||||
@@ -176,20 +176,20 @@ function RenderCinePlayer({
|
||||
return;
|
||||
}
|
||||
|
||||
const handleTimePointIndexChange = evt => {
|
||||
const { volumeId, timePointIndex, numTimePoints, splittingTag } = evt.detail;
|
||||
setDynamicInfo({ volumeId, timePointIndex, numTimePoints, label: splittingTag });
|
||||
const handleDimensionGroupChange = evt => {
|
||||
const { volumeId, dimensionGroupNumber, numDimensionGroups, splittingTag } = evt.detail;
|
||||
setDynamicInfo({ volumeId, dimensionGroupNumber, numDimensionGroups, label: splittingTag });
|
||||
};
|
||||
|
||||
eventTarget.addEventListener(
|
||||
Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED,
|
||||
handleTimePointIndexChange
|
||||
Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED,
|
||||
handleDimensionGroupChange
|
||||
);
|
||||
|
||||
return () => {
|
||||
eventTarget.removeEventListener(
|
||||
Enums.Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED,
|
||||
handleTimePointIndexChange
|
||||
Enums.Events.DYNAMIC_VOLUME_DIMENSION_GROUP_CHANGED,
|
||||
handleDimensionGroupChange
|
||||
);
|
||||
};
|
||||
}, [dynamicInfo]);
|
||||
@@ -199,17 +199,17 @@ function RenderCinePlayer({
|
||||
return;
|
||||
}
|
||||
|
||||
const { volumeId, timePointIndex, numTimePoints, splittingTag } = dynamicInfo || {};
|
||||
const { volumeId, dimensionGroupNumber, numDimensionGroups, splittingTag } = dynamicInfo || {};
|
||||
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 { volumeId, timePointIndex } = props;
|
||||
const { volumeId, dimensionGroupNumber } = props;
|
||||
const volume = cache.getVolume(volumeId, true);
|
||||
volume.timePointIndex = timePointIndex;
|
||||
volume.dimensionGroupNumber = dimensionGroupNumber;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback, useEffect, useRef, useState, ReactElement } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, ProgressLoadingBar } from '@ohif/ui';
|
||||
import { useSystem } from '@ohif/core';
|
||||
import { Button } from '@ohif/ui';
|
||||
import { Icons } from '@ohif/ui-next';
|
||||
import DicomFileUploader, {
|
||||
EVENTS,
|
||||
@@ -40,6 +41,11 @@ function DicomUploadProgress({
|
||||
dicomFileUploaderArr,
|
||||
onComplete,
|
||||
}: DicomUploadProgressProps): ReactElement {
|
||||
const { servicesManager } = useSystem();
|
||||
|
||||
const ProgressLoadingBar =
|
||||
servicesManager.services.customizationService.getCustomization('ui.progressLoadingBar');
|
||||
|
||||
const [totalUploadSize] = useState(
|
||||
dicomFileUploaderArr.reduce((acc, fileUploader) => acc + fileUploader.getFileSize(), 0)
|
||||
);
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React from 'react';
|
||||
import { useViewportActionCornersContext } from '../contextProviders/ViewportActionCornersProvider';
|
||||
import { ViewportActionCorners } from '@ohif/ui';
|
||||
import { useSystem } from '@ohif/core';
|
||||
|
||||
export type OHIFViewportActionCornersProps = {
|
||||
viewportId: string;
|
||||
};
|
||||
|
||||
function OHIFViewportActionCorners({ viewportId }: OHIFViewportActionCornersProps) {
|
||||
const { servicesManager } = useSystem();
|
||||
const [viewportActionCornersState] = useViewportActionCornersContext();
|
||||
|
||||
const ViewportActionCorners =
|
||||
servicesManager.services.customizationService.getCustomization('ui.viewportActionCorner');
|
||||
if (!viewportActionCornersState[viewportId]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import viewportActionCornersService from '../services/ViewportActionCornersService/ViewportActionCornersService';
|
||||
|
||||
export default {
|
||||
'viewportActionMenu.windowLevelActionMenu': {
|
||||
enabled: true,
|
||||
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||
},
|
||||
'viewportActionMenu.segmentationOverlay': {
|
||||
enabled: true,
|
||||
location: viewportActionCornersService.LOCATIONS.topRight,
|
||||
},
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import colorbarCustomization from './customizations/colorbarCustomization';
|
||||
import windowLevelPresetsCustomization from './customizations/windowLevelPresetsCustomization';
|
||||
import miscCustomization from './customizations/miscCustomization';
|
||||
import windowLevelActionMenuCustomization from './customizations/windowLevelActionMenuCustomization';
|
||||
import viewportActionMenuCustomizations from './customizations/viewportActionMenuCustomizations';
|
||||
|
||||
function getCustomizationModule({ commandsManager, servicesManager }) {
|
||||
return [
|
||||
@@ -26,6 +27,7 @@ function getCustomizationModule({ commandsManager, servicesManager }) {
|
||||
...windowLevelPresetsCustomization,
|
||||
...miscCustomization,
|
||||
...windowLevelActionMenuCustomization,
|
||||
...viewportActionMenuCustomizations,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import { Enums } from '@cornerstonejs/tools';
|
||||
|
||||
const getToggledClassName = (isToggled: boolean) => {
|
||||
return isToggled
|
||||
? '!text-primary-active'
|
||||
: '!text-common-bright hover:!bg-primary-dark hover:text-primary-light';
|
||||
};
|
||||
import { utils } from '@ohif/ui-next';
|
||||
|
||||
const getDisabledState = (disabledText?: string) => ({
|
||||
disabled: true,
|
||||
className: '!text-common-bright ohif-disabled',
|
||||
disabledText: disabledText ?? 'Not available on the current viewport',
|
||||
});
|
||||
|
||||
@@ -93,9 +87,6 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
className: isPrimaryActive
|
||||
? '!text-black bg-primary-light rounded'
|
||||
: '!text-common-bright hover:!bg-primary-dark hover:!text-primary-light rounded',
|
||||
// Todo: isActive right now is used for nested buttons where the primary
|
||||
// button needs to be fully rounded (vs partial rounded) when active
|
||||
// otherwise it does not have any other use
|
||||
@@ -153,9 +144,9 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
},
|
||||
{
|
||||
name: 'evaluate.action',
|
||||
evaluate: ({ viewportId, button }) => {
|
||||
evaluate: () => {
|
||||
return {
|
||||
className: '!text-common-bright hover:!bg-primary-dark hover:text-primary-light',
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -190,7 +181,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
|
||||
if (!synchronizers?.length) {
|
||||
return {
|
||||
className: getToggledClassName(false),
|
||||
className: utils.getToggledClassName(false),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -204,7 +195,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
|
||||
if (!synchronizers?.length) {
|
||||
return {
|
||||
className: getToggledClassName(false),
|
||||
className: utils.getToggledClassName(false),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -216,7 +207,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
const isEnabled = synchronizer?._enabled;
|
||||
|
||||
return {
|
||||
className: getToggledClassName(isEnabled),
|
||||
className: utils.getToggledClassName(isEnabled),
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -239,14 +230,13 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
if (!prop) {
|
||||
return {
|
||||
disabled: false,
|
||||
className: '!text-common-bright hover:!bg-primary-dark hover:text-primary-light',
|
||||
};
|
||||
}
|
||||
|
||||
const isToggled = prop;
|
||||
|
||||
return {
|
||||
className: getToggledClassName(isToggled),
|
||||
className: utils.getToggledClassName(isToggled),
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -275,7 +265,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
className: getToggledClassName(isMpr),
|
||||
className: utils.getToggledClassName(isMpr),
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -304,6 +294,6 @@ function _evaluateToggle({
|
||||
const isOff = offModes.includes(toolGroup.getToolOptions(toolName).mode);
|
||||
|
||||
return {
|
||||
className: getToggledClassName(!isOff),
|
||||
className: utils.getToggledClassName(!isOff),
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const fourUp = {
|
||||
id: 'fourUp',
|
||||
locked: true,
|
||||
@@ -46,17 +48,7 @@ export const fourUp = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -72,6 +64,7 @@ export const fourUp = {
|
||||
customViewportProps: {
|
||||
hideOverlays: true,
|
||||
},
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -94,17 +87,7 @@ export const fourUp = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -120,17 +103,7 @@ export const fourUp = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
|
||||
@@ -55,6 +55,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
viewports: [
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R0_C0',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -91,6 +92,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R0_C1',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -127,6 +129,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R0_C2',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -163,6 +166,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R0_C3',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -199,6 +203,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R1_C0',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -235,6 +240,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R1_C1',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -271,6 +277,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R1_C2',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -307,6 +314,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R1_C3',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -343,6 +351,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R2_C0',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -379,6 +388,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R2_C1',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -415,6 +425,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R2_C2',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -451,6 +462,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R2_C3',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -487,6 +499,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R3_C0',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -523,6 +536,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R3_C1',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -559,6 +573,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R3_C2',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
@@ -595,6 +610,7 @@ const frameView: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'custom_R3_C3',
|
||||
toolGroupId: 'default',
|
||||
syncGroups: [
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const main3D = {
|
||||
id: 'main3D',
|
||||
locked: true,
|
||||
@@ -94,17 +96,7 @@ export const main3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -120,17 +112,7 @@ export const main3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -146,17 +128,7 @@ export const main3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Types } from '@ohif/core';
|
||||
|
||||
const VOI_SYNC_GROUP = {
|
||||
export const VOI_SYNC_GROUP = {
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
@@ -10,7 +10,7 @@ const VOI_SYNC_GROUP = {
|
||||
},
|
||||
};
|
||||
|
||||
const HYDRATE_SEG_SYNC_GROUP = {
|
||||
export const HYDRATE_SEG_SYNC_GROUP = {
|
||||
type: 'hydrateseg',
|
||||
id: 'sameFORId',
|
||||
source: true,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const mprAnd3DVolumeViewport = {
|
||||
id: 'mprAnd3DVolumeViewport',
|
||||
locked: true,
|
||||
@@ -53,17 +55,7 @@ export const mprAnd3DVolumeViewport = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -79,6 +71,7 @@ export const mprAnd3DVolumeViewport = {
|
||||
customViewportProps: {
|
||||
hideOverlays: true,
|
||||
},
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -101,17 +94,7 @@ export const mprAnd3DVolumeViewport = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -127,17 +110,7 @@ export const mprAnd3DVolumeViewport = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const only3D = {
|
||||
id: 'only3D',
|
||||
locked: true,
|
||||
@@ -45,6 +47,7 @@ export const only3D = {
|
||||
orientation: 'coronal',
|
||||
customViewportProps: {
|
||||
hideOverlays: true,
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
},
|
||||
displaySets: [
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const primary3D = {
|
||||
id: 'primary3D',
|
||||
locked: true,
|
||||
@@ -94,17 +96,7 @@ export const primary3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -120,17 +112,7 @@ export const primary3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -146,17 +128,7 @@ export const primary3D = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HYDRATE_SEG_SYNC_GROUP, VOI_SYNC_GROUP } from './mpr';
|
||||
|
||||
export const primaryAxial = {
|
||||
id: 'primaryAxial',
|
||||
locked: true,
|
||||
@@ -66,17 +68,7 @@ export const primaryAxial = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -92,17 +84,7 @@ export const primaryAxial = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
@@ -118,17 +100,7 @@ export const primaryAxial = {
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [
|
||||
{
|
||||
type: 'voi',
|
||||
id: 'mpr',
|
||||
source: true,
|
||||
target: true,
|
||||
options: {
|
||||
syncColormap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
|
||||
@@ -54,6 +54,7 @@ import PanelMeasurement from './panels/PanelMeasurement';
|
||||
import DicomUpload from './components/DicomUpload/DicomUpload';
|
||||
import { useSegmentations } from './hooks/useSegmentations';
|
||||
import { StudySummaryFromMetadata } from './components/StudySummaryFromMetadata';
|
||||
import utils from './utils';
|
||||
|
||||
const { imageRetrieveMetadataProvider } = cornerstone.utilities;
|
||||
|
||||
@@ -160,7 +161,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
ViewportActionCornersProvider
|
||||
);
|
||||
|
||||
const { syncGroupService, customizationService } = servicesManager.services;
|
||||
const { syncGroupService } = servicesManager.services;
|
||||
syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer);
|
||||
|
||||
return init.call(this, props);
|
||||
@@ -254,5 +255,6 @@ export {
|
||||
PanelMeasurement,
|
||||
DicomUpload,
|
||||
StudySummaryFromMetadata,
|
||||
utils,
|
||||
};
|
||||
export default cornerstoneExtension;
|
||||
@@ -61,7 +61,11 @@ export default function PanelSegmentation({
|
||||
},
|
||||
|
||||
storeSegmentation: async segmentationId => {
|
||||
commandsManager.run('storeSegmentation', { segmentationId });
|
||||
commandsManager.run({
|
||||
commandName: 'storeSegmentation',
|
||||
commandOptions: { segmentationId },
|
||||
context: 'CORNERSTONE',
|
||||
});
|
||||
},
|
||||
|
||||
onSegmentationDownloadRTSS: segmentationId => {
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '@cornerstonejs/tools';
|
||||
import { PubSubService, Types as OHIFTypes } from '@ohif/core';
|
||||
import i18n from '@ohif/i18n';
|
||||
import { easeInOutBell, reverseEaseInOutBell } from '../../utils/transitions';
|
||||
import { easeInOutBell, easeInOutBellRelative } from '../../utils/transitions';
|
||||
import { mapROIContoursToRTStructData } from './RTSTRUCT/mapROIContoursToRTStructData';
|
||||
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
|
||||
import { addColorLUT } from '@cornerstonejs/tools/segmentation/addColorLUT';
|
||||
@@ -809,7 +809,8 @@ class SegmentationService extends PubSubService {
|
||||
if (!segmentIndex) {
|
||||
// grab the next available segment index based on the object keys,
|
||||
// so basically get the highest segment index value + 1
|
||||
segmentIndex = Math.max(...Object.keys(csSegmentation.segments).map(Number)) + 1;
|
||||
const segmentKeys = Object.keys(csSegmentation.segments);
|
||||
segmentIndex = segmentKeys.length === 0 ? 1 : Math.max(...segmentKeys.map(Number)) + 1;
|
||||
}
|
||||
|
||||
// update the segmentation
|
||||
@@ -1636,10 +1637,7 @@ class SegmentationService extends PubSubService {
|
||||
const startTime = performance.now();
|
||||
|
||||
const prevStyle = cstSegmentation.config.style.getStyle({
|
||||
viewportId,
|
||||
segmentationId,
|
||||
type: CONTOUR,
|
||||
segmentIndex,
|
||||
}) as ContourStyle;
|
||||
|
||||
const prevOutlineWidth = prevStyle.outlineWidth;
|
||||
@@ -1649,18 +1647,11 @@ class SegmentationService extends PubSubService {
|
||||
const animate = (currentTime: number) => {
|
||||
const progress = (currentTime - startTime) / animationLength;
|
||||
if (progress >= 1) {
|
||||
cstSegmentation.config.style.setStyle(
|
||||
{
|
||||
segmentationId,
|
||||
segmentIndex,
|
||||
type: CONTOUR,
|
||||
},
|
||||
{}
|
||||
);
|
||||
cstSegmentation.config.style.resetToGlobalStyle();
|
||||
return;
|
||||
}
|
||||
|
||||
const reversedProgress = reverseEaseInOutBell(progress, baseline);
|
||||
const reversedProgress = easeInOutBellRelative(progress, baseline, prevOutlineWidth);
|
||||
|
||||
cstSegmentation.config.style.setStyle(
|
||||
{
|
||||
|
||||
@@ -38,6 +38,8 @@ const EVENTS = {
|
||||
VIEWPORT_VOLUMES_CHANGED: 'event::cornerstoneViewportService:viewportVolumesChanged',
|
||||
};
|
||||
|
||||
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: true };
|
||||
|
||||
/**
|
||||
* Handles cornerstone viewport logic including enabling, disabling, and
|
||||
* updating the viewport.
|
||||
@@ -1141,7 +1143,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
): void {
|
||||
const viewRef = positionPresentation?.viewReference;
|
||||
if (viewRef) {
|
||||
viewport.setViewReference(viewRef);
|
||||
if (viewport.isReferenceViewable(viewRef, WITH_NAVIGATION)) {
|
||||
viewport.setViewReference(viewRef);
|
||||
} else {
|
||||
console.warn('Unable to apply reference viewable', viewRef);
|
||||
}
|
||||
}
|
||||
|
||||
const viewPresentation = positionPresentation?.viewPresentation;
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import { useEffect, useState, memo } from 'react';
|
||||
import { useEffect, useState, memo, useCallback } from 'react';
|
||||
|
||||
const ActiveViewportBehavior = memo(
|
||||
({ servicesManager, viewportId }: withAppTypes<{ viewportId: string }>) => {
|
||||
const { displaySetService, cineService, viewportGridService, customizationService } =
|
||||
servicesManager.services;
|
||||
const {
|
||||
displaySetService,
|
||||
cineService,
|
||||
viewportGridService,
|
||||
customizationService,
|
||||
cornerstoneViewportService,
|
||||
} = servicesManager.services;
|
||||
|
||||
const [activeViewportId, setActiveViewportId] = useState(viewportId);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = viewportGridService.subscribe(
|
||||
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
|
||||
({ viewportId }) => setActiveViewportId(viewportId)
|
||||
);
|
||||
|
||||
return () => subscription.unsubscribe();
|
||||
}, [viewportId, viewportGridService]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleCineEnable = useCallback(() => {
|
||||
if (cineService.isViewportCineClosed(activeViewportId)) {
|
||||
return;
|
||||
}
|
||||
@@ -54,6 +50,32 @@ const ActiveViewportBehavior = memo(
|
||||
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;
|
||||
},
|
||||
arePropsEqual
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { handleSegmentChange } from './segmentUtils';
|
||||
|
||||
const utils = {
|
||||
handleSegmentChange,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
@@ -1,6 +1,8 @@
|
||||
import { cache, imageLoadPoolManager, Enums } from '@cornerstonejs/core';
|
||||
import getInterleavedFrames from './getInterleavedFrames';
|
||||
import { compact, flatten, zip } from 'lodash';
|
||||
import zip from 'lodash.zip';
|
||||
import compact from 'lodash.compact';
|
||||
import flatten from 'lodash.flatten';
|
||||
|
||||
// Map of volumeId and SeriesInstanceId
|
||||
const volumeIdMapsToLoad = new Map<string, string>();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { cache, imageLoadPoolManager, Enums } from '@cornerstonejs/core';
|
||||
import { compact, flatten, zip } from 'lodash';
|
||||
import zip from 'lodash.zip';
|
||||
import compact from 'lodash.compact';
|
||||
import flatten from 'lodash.flatten';
|
||||
|
||||
// Map of volumeId and SeriesInstanceId
|
||||
const volumeIdMapsToLoad = new Map<string, string>();
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import SegmentationServiceType from '../services/SegmentationService';
|
||||
|
||||
export const handleSegmentChange = ({
|
||||
direction,
|
||||
segDisplaySet,
|
||||
viewportId,
|
||||
selectedSegmentObjectIndex,
|
||||
segmentationService,
|
||||
}: {
|
||||
direction: number;
|
||||
segDisplaySet: AppTypes.DisplaySet;
|
||||
viewportId: string;
|
||||
selectedSegmentObjectIndex: number;
|
||||
segmentationService: SegmentationServiceType;
|
||||
}) => {
|
||||
const segmentationId = segDisplaySet.displaySetInstanceUID;
|
||||
const segmentation = segmentationService.getSegmentation(segmentationId);
|
||||
|
||||
const { segments } = segmentation;
|
||||
|
||||
const numberOfSegments = Object.keys(segments).length;
|
||||
|
||||
// Get activeSegment each time because the user can select any segment from the list and thus the index should be updated
|
||||
const activeSegment = segmentationService.getActiveSegment(viewportId);
|
||||
if (activeSegment) {
|
||||
// from the activeSegment get the actual object array index to be used
|
||||
selectedSegmentObjectIndex = Object.values(segments).findIndex(
|
||||
segment => segment.segmentIndex === activeSegment.segmentIndex
|
||||
);
|
||||
}
|
||||
let newSelectedSegmentIndex = selectedSegmentObjectIndex + direction;
|
||||
|
||||
// Handle looping through list of segments
|
||||
if (newSelectedSegmentIndex > numberOfSegments - 1) {
|
||||
newSelectedSegmentIndex = 0;
|
||||
} else if (newSelectedSegmentIndex < 0) {
|
||||
newSelectedSegmentIndex = numberOfSegments - 1;
|
||||
}
|
||||
|
||||
// Convert segmentationId from object array index to property value of type Segment
|
||||
// Functions below use the segmentIndex object attribute so we have to do the conversion
|
||||
const segmentIndex = Object.values(segments)[newSelectedSegmentIndex]?.segmentIndex;
|
||||
|
||||
segmentationService.setActiveSegment(segmentationId, segmentIndex);
|
||||
segmentationService.jumpToSegmentCenter(segmentationId, segmentIndex, viewportId);
|
||||
selectedSegmentObjectIndex = newSelectedSegmentIndex;
|
||||
};
|
||||
@@ -34,3 +34,30 @@ export function reverseEaseInOutBell(x: number, baseline: number): number {
|
||||
const y = easeInOutBell(x, baseline);
|
||||
return -y + 1 + baseline;
|
||||
}
|
||||
|
||||
export function easeInOutBellRelative(
|
||||
x: number,
|
||||
baseline: number,
|
||||
prevOutlineWidth: number
|
||||
): number {
|
||||
const range = baseline - prevOutlineWidth;
|
||||
|
||||
if (x < 1 / 4) {
|
||||
return prevOutlineWidth + 4 * Math.pow(2 * x, 3) * range;
|
||||
} else if (x < 1 / 2) {
|
||||
return prevOutlineWidth + (1 - Math.pow(-4 * x + 2, 3) / 2) * range;
|
||||
} else if (x < 3 / 4) {
|
||||
return prevOutlineWidth + (1 - Math.pow(4 * x - 2, 3) / 2) * range;
|
||||
} else {
|
||||
return prevOutlineWidth + -4 * Math.pow(2 * x - 2, 3) * range;
|
||||
}
|
||||
}
|
||||
|
||||
export function reverseEaseInOutBellRelative(
|
||||
x: number,
|
||||
baseline: number,
|
||||
prevOutlineWidth: number
|
||||
): number {
|
||||
const y = easeInOutBellRelative(x, baseline, prevOutlineWidth);
|
||||
return y;
|
||||
}
|
||||
@@ -3,6 +3,325 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sr:** sr hydration and load was not working, Screenshot Comparison, and Testing ([#4814](https://github.com/OHIF/Viewers/issues/4814)) ([9233143](https://github.com/OHIF/Viewers/commit/9233143b9da5850080365e1526e24b44e9910075))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hotkeys:** Migrate hotkeys to customization service and fix issues with overrides ([#4777](https://github.com/OHIF/Viewers/issues/4777)) ([3e6913b](https://github.com/OHIF/Viewers/commit/3e6913b097569280a5cc2fa5bbe4add52f149305))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cache thumbnail in display set ([#4782](https://github.com/OHIF/Viewers/issues/4782)) ([2410c6a](https://github.com/OHIF/Viewers/commit/2410c6a50904c1235993900e837876cc26af019b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* lodash dependencies ([#4791](https://github.com/OHIF/Viewers/issues/4791)) ([4e16099](https://github.com/OHIF/Viewers/commit/4e16099ad3ab777b09f6ac8f181025cfd656ab6b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* improve dicom tag browser with nested rows ([#4451](https://github.com/OHIF/Viewers/issues/4451)) ([0b5836c](https://github.com/OHIF/Viewers/commit/0b5836ca1a908e152336752672b196f0d533f4f9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add commandsManager to MoreDropdownMenu onClick props ([#4765](https://github.com/OHIF/Viewers/issues/4765)) ([bbf1a19](https://github.com/OHIF/Viewers/commit/bbf1a19676b2b345a0f911dde319e5ffefe29fa6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** customization option for viewport notification ([#4638](https://github.com/OHIF/Viewers/issues/4638)) ([8acbd76](https://github.com/OHIF/Viewers/commit/8acbd760d801dcaf624c5d9fb636a029201b91e1))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement label auto-completion:** Customization of measurement label auto-completion fails for measurements following arrow annotations. ([#4739](https://github.com/OHIF/Viewers/issues/4739)) ([e035ef1](https://github.com/OHIF/Viewers/commit/e035ef1dcc72ecbe2a757e3b814551d768d7e610))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **store-segmentation:** storing segmentations was hitting the wrong command resulting in an undefined datasource ([#4755](https://github.com/OHIF/Viewers/issues/4755)) ([9b8e5cf](https://github.com/OHIF/Viewers/commit/9b8e5cfd1a6121a58991c0f75660a2fd9913a4e7))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **customization:** enable custom onDropHandler for viewportGrid ([#4641](https://github.com/OHIF/Viewers/issues/4641)) ([054b262](https://github.com/OHIF/Viewers/commit/054b262e9cbeb0f44de65d05641efe1e8944a4f5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** Update dcmjs library and improve documentation links ([#4741](https://github.com/OHIF/Viewers/issues/4741)) ([d554f02](https://github.com/OHIF/Viewers/commit/d554f02f7cdb876e4132fb94e3b3df8d11b7bb5c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **side-panels:** Added resize handle interactive feedback for side panels ([#4734](https://github.com/OHIF/Viewers/issues/4734)) ([6abb095](https://github.com/OHIF/Viewers/commit/6abb095b8a39c5ae4f8df8852b3ddb3249ec463f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-default
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-default",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "Common/default features and functionality for basic image viewing",
|
||||
"author": "OHIF Core Team",
|
||||
"license": "MIT",
|
||||
@@ -32,8 +32,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"dcmjs": "*",
|
||||
"dicomweb-client": "^0.10.4",
|
||||
"prop-types": "^15.6.2",
|
||||
@@ -46,6 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@cornerstonejs/calculate-suv": "^1.1.0"
|
||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.uniqby": "^4.7.0"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { ReactElement, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, InputFilterText, LoadingIndicatorProgress } from '@ohif/ui';
|
||||
import { useSystem } from '@ohif/core';
|
||||
import { Button, InputFilterText } from '@ohif/ui';
|
||||
import { Icons } from '@ohif/ui-next';
|
||||
import { Types } from '@ohif/core';
|
||||
|
||||
@@ -16,6 +17,7 @@ function ItemListComponent({
|
||||
itemList,
|
||||
onItemClicked,
|
||||
}: ItemListComponentProps): ReactElement {
|
||||
const { servicesManager } = useSystem();
|
||||
const { t } = useTranslation('DataSourceConfiguration');
|
||||
const [filterValue, setFilterValue] = useState('');
|
||||
|
||||
@@ -23,6 +25,10 @@ function ItemListComponent({
|
||||
setFilterValue('');
|
||||
}, [itemList]);
|
||||
|
||||
const LoadingIndicatorProgress = servicesManager.services.customizationService.getCustomization(
|
||||
'ui.loadingIndicatorProgress'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-[1px] grow flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
Icons,
|
||||
Button,
|
||||
} from '@ohif/ui-next';
|
||||
@@ -11,13 +12,40 @@ import {
|
||||
* The default sub-menu appearance and setup is defined here, but this can be
|
||||
* replaced by
|
||||
*/
|
||||
const getMenuItemsDefault = ({ commandsManager, items, servicesManager, ...props }) => {
|
||||
const getMenuItemsDefault = ({
|
||||
commandsManager,
|
||||
items,
|
||||
servicesManager,
|
||||
...props
|
||||
}: withAppTypes) => {
|
||||
const { customizationService } = servicesManager.services;
|
||||
|
||||
// This allows replacing the default child item for menus, whereas the entire
|
||||
// getMenuItems can also be replaced by providing it to the MoreDropdownMenu
|
||||
const menuContent = customizationService.getCustomization('ohif.menuContent');
|
||||
|
||||
// Default menu item component if none is provided through customization
|
||||
|
||||
const DefaultMenuItem = ({
|
||||
item,
|
||||
}: {
|
||||
item: {
|
||||
id: string;
|
||||
label: string;
|
||||
iconName: string;
|
||||
onClick: ({ commandsManager, ...props }: withAppTypes) => () => void;
|
||||
};
|
||||
}) => (
|
||||
<DropdownMenuItem onClick={() => item.onClick({ commandsManager, ...props })}>
|
||||
<div className="flex items-center gap-2">
|
||||
{item.iconName && <Icons.ByName name={item.iconName} />}
|
||||
<span>{item.label}</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
|
||||
const MenuItemComponent = menuContent?.content || DefaultMenuItem;
|
||||
|
||||
return (
|
||||
<DropdownMenuContent
|
||||
hideWhenDetached
|
||||
@@ -27,15 +55,15 @@ const getMenuItemsDefault = ({ commandsManager, items, servicesManager, ...props
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
{items?.map((item, index) =>
|
||||
React.createElement(menuContent.content, {
|
||||
key: item.id || `menu-item-${index}`,
|
||||
item,
|
||||
commandsManager,
|
||||
servicesManager,
|
||||
...props,
|
||||
})
|
||||
)}
|
||||
{items?.map((item, index) => (
|
||||
<MenuItemComponent
|
||||
key={item.id || `menu-item-${index}`}
|
||||
item={item}
|
||||
commandsManager={commandsManager}
|
||||
servicesManager={servicesManager}
|
||||
{...props}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as ContextMenuItemsBuilder from './ContextMenuItemsBuilder';
|
||||
import ContextMenu from '../../../../platform/ui/src/components/ContextMenu/ContextMenu';
|
||||
import { CommandsManager } from '@ohif/core';
|
||||
import { annotation as CsAnnotation } from '@cornerstonejs/tools';
|
||||
import { Menu, MenuItem, Point, ContextMenuProps } from './types';
|
||||
@@ -72,6 +71,8 @@ export default class ContextMenuController {
|
||||
menuId
|
||||
);
|
||||
|
||||
const ContextMenu = this.services.customizationService.getCustomization('ui.contextMenu');
|
||||
|
||||
this.services.uiDialogService.dismiss({ id: 'context-menu' });
|
||||
this.services.uiDialogService.create({
|
||||
id: 'context-menu',
|
||||
|
||||
@@ -1,30 +1,44 @@
|
||||
import dcmjs from 'dcmjs';
|
||||
import moment from 'moment';
|
||||
import React, { useState, useMemo, useEffect } from 'react';
|
||||
import { classes } from '@ohif/core';
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { classes, Types } from '@ohif/core';
|
||||
import { InputFilterText } from '@ohif/ui';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { Select, SelectTrigger, SelectContent, SelectItem, Slider } from '@ohif/ui-next';
|
||||
|
||||
import DicomTagTable from './DicomTagTable';
|
||||
import './DicomTagBrowser.css';
|
||||
|
||||
export type Row = {
|
||||
uid: string;
|
||||
tag: string;
|
||||
valueRepresentation: string;
|
||||
keyword: string;
|
||||
value: string;
|
||||
isVisible: boolean;
|
||||
depth: number;
|
||||
parents?: string[];
|
||||
children?: string[];
|
||||
areChildrenVisible?: true;
|
||||
};
|
||||
|
||||
let rowCounter = 0;
|
||||
const generateRowId = () => `row_${++rowCounter}`;
|
||||
|
||||
const { ImageSet } = classes;
|
||||
const { DicomMetaDictionary } = dcmjs.data;
|
||||
const { nameMap } = DicomMetaDictionary;
|
||||
|
||||
const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
// The column indices that are to be excluded during a filter of the table.
|
||||
// At present the column indices are:
|
||||
// 0: DICOM tag
|
||||
// 1: VR
|
||||
// 2: Keyword
|
||||
// 3: Value
|
||||
const excludedColumnIndicesForFilter: Set<number> = new Set([1]);
|
||||
|
||||
const DicomTagBrowser = ({
|
||||
displaySets,
|
||||
displaySetInstanceUID,
|
||||
}: {
|
||||
displaySets: Types.DisplaySet[];
|
||||
displaySetInstanceUID: string;
|
||||
}) => {
|
||||
const [selectedDisplaySetInstanceUID, setSelectedDisplaySetInstanceUID] =
|
||||
useState(displaySetInstanceUID);
|
||||
const [instanceNumber, setInstanceNumber] = useState(1);
|
||||
const [shouldShowInstanceList, setShouldShowInstanceList] = useState(false);
|
||||
const [filterValue, setFilterValue] = useState('');
|
||||
|
||||
const onSelectChange = value => {
|
||||
@@ -36,9 +50,6 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID
|
||||
);
|
||||
|
||||
const isImageStack = _isImageStack(activeDisplaySet);
|
||||
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
||||
|
||||
const displaySetList = useMemo(() => {
|
||||
displaySets.sort((a, b) => a.SeriesNumber - b.SeriesNumber);
|
||||
return displaySets.map(displaySet => {
|
||||
@@ -64,48 +75,53 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
});
|
||||
}, [displaySets]);
|
||||
|
||||
const getMetadata = useCallback(
|
||||
isImageStack => {
|
||||
if (isImageStack) {
|
||||
return activeDisplaySet.images[instanceNumber - 1];
|
||||
}
|
||||
return activeDisplaySet.instance || activeDisplaySet;
|
||||
},
|
||||
[activeDisplaySet, instanceNumber]
|
||||
);
|
||||
|
||||
const rows = useMemo(() => {
|
||||
let metadata;
|
||||
if (isImageStack) {
|
||||
metadata = activeDisplaySet.images[instanceNumber - 1];
|
||||
} else {
|
||||
metadata = activeDisplaySet.instance || activeDisplaySet;
|
||||
}
|
||||
const isImageStack = activeDisplaySet instanceof ImageSet;
|
||||
const metadata = getMetadata(isImageStack);
|
||||
|
||||
setShouldShowInstanceList(isImageStack && activeDisplaySet.images.length > 1);
|
||||
const tags = getSortedTags(metadata);
|
||||
return getFormattedRowsFromTags(tags, metadata);
|
||||
}, [instanceNumber, selectedDisplaySetInstanceUID]);
|
||||
const rows = getFormattedRowsFromTags({ tags, metadata, depth: 0 });
|
||||
return rows;
|
||||
}, [getMetadata, activeDisplaySet]);
|
||||
|
||||
const filteredRows = useMemo(() => {
|
||||
if (!filterValue) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
const filterValueLowerCase = filterValue.toLowerCase();
|
||||
return rows.filter(row => {
|
||||
return row.reduce((keepRow, col, colIndex) => {
|
||||
if (keepRow) {
|
||||
// We are already keeping the row, why do more work so return now.
|
||||
return keepRow;
|
||||
}
|
||||
const matchedRowIds = new Set();
|
||||
|
||||
if (excludedColumnIndicesForFilter.has(colIndex)) {
|
||||
return keepRow;
|
||||
}
|
||||
const propertiesToCheck = ['tag', 'valueRepresentation', 'keyword', 'value'];
|
||||
|
||||
return keepRow || col.toLowerCase().includes(filterValueLowerCase);
|
||||
}, false);
|
||||
});
|
||||
}, [rows, filterValue]);
|
||||
const setIsMatched = row => {
|
||||
const isDirectMatch = propertiesToCheck.some(propertyName =>
|
||||
row[propertyName]?.toLowerCase().includes(filterValueLowerCase)
|
||||
);
|
||||
|
||||
const debouncedSetFilterValue = useMemo(() => {
|
||||
return debounce(setFilterValue, 200);
|
||||
}, []);
|
||||
if (!isDirectMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
debouncedSetFilterValue?.cancel();
|
||||
matchedRowIds.add(row.uid);
|
||||
|
||||
[...(row.parents ?? []), ...(row.children ?? [])].forEach(uid => matchedRowIds.add(uid));
|
||||
};
|
||||
}, []);
|
||||
|
||||
const filterValueLowerCase = filterValue.toLowerCase();
|
||||
rows.forEach(setIsMatched);
|
||||
return rows.filter(row => matchedRowIds.has(row.uid));
|
||||
}, [rows, filterValue]);
|
||||
|
||||
return (
|
||||
<div className="dicom-tag-browser-content bg-muted">
|
||||
@@ -136,10 +152,10 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{showInstanceList && (
|
||||
{shouldShowInstanceList && (
|
||||
<div className="mx-auto flex w-1/5 flex-col">
|
||||
<span className="text-muted-foreground flex h-6 items-center text-xs">
|
||||
Instance Number ({instanceNumber} of {activeDisplaySet.images.length})
|
||||
Instance Number ({instanceNumber} of {activeDisplaySet?.images?.length})
|
||||
</span>
|
||||
<Slider
|
||||
value={[instanceNumber]}
|
||||
@@ -147,7 +163,7 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
setInstanceNumber(value);
|
||||
}}
|
||||
min={1}
|
||||
max={activeDisplaySet.images.length}
|
||||
max={activeDisplaySet?.images?.length}
|
||||
step={1}
|
||||
className="pt-4"
|
||||
/>
|
||||
@@ -169,22 +185,33 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||
);
|
||||
};
|
||||
|
||||
function getFormattedRowsFromTags(tags, metadata) {
|
||||
const rows = [];
|
||||
function getFormattedRowsFromTags({ tags, metadata, depth, parents }) {
|
||||
const rows: Row[] = [];
|
||||
|
||||
tags.forEach(tagInfo => {
|
||||
const uid = generateRowId();
|
||||
if (tagInfo.vr === 'SQ') {
|
||||
rows.push([`${tagInfo.tagIndent}${tagInfo.tag}`, tagInfo.vr, tagInfo.keyword, '']);
|
||||
|
||||
const { values } = tagInfo;
|
||||
|
||||
values.forEach((item, index) => {
|
||||
const formatedRowsFromTags = getFormattedRowsFromTags(item, metadata);
|
||||
|
||||
rows.push([`${item[0].tagIndent}(FFFE,E000)`, '', `Item #${index}`, '']);
|
||||
|
||||
rows.push(...formatedRowsFromTags);
|
||||
});
|
||||
const children = tagInfo.values.flatMap(value =>
|
||||
getFormattedRowsFromTags({
|
||||
tags: value,
|
||||
metadata,
|
||||
depth: depth + 1,
|
||||
parents: parents ? [...parents, uid] : [uid],
|
||||
})
|
||||
);
|
||||
const row: Row = {
|
||||
uid,
|
||||
tag: tagInfo.tag,
|
||||
valueRepresentation: tagInfo.vr,
|
||||
keyword: tagInfo.keyword,
|
||||
value: '',
|
||||
depth,
|
||||
isVisible: true,
|
||||
areChildrenVisible: true,
|
||||
children: children.map(child => child.uid),
|
||||
parents,
|
||||
};
|
||||
rows.push(row, ...children);
|
||||
} else {
|
||||
if (tagInfo.vr === 'xs') {
|
||||
try {
|
||||
@@ -192,10 +219,20 @@ function getFormattedRowsFromTags(tags, metadata) {
|
||||
const originalTagInfo = metadata[tag];
|
||||
tagInfo.vr = originalTagInfo.vr;
|
||||
} catch (error) {
|
||||
console.error(`Failed to parse value representation for tag '${tagInfo.keyword}'`);
|
||||
console.warn(`Failed to parse value representation for tag '${tagInfo.keyword}'`);
|
||||
}
|
||||
}
|
||||
rows.push([`${tagInfo.tagIndent}${tagInfo.tag}`, tagInfo.vr, tagInfo.keyword, tagInfo.value]);
|
||||
const row: Row = {
|
||||
uid,
|
||||
tag: tagInfo.tag,
|
||||
valueRepresentation: tagInfo.vr,
|
||||
keyword: tagInfo.keyword,
|
||||
value: tagInfo.value,
|
||||
depth,
|
||||
isVisible: true,
|
||||
parents,
|
||||
};
|
||||
rows.push(row);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -216,16 +253,6 @@ function getRows(metadata, depth = 0) {
|
||||
|
||||
const keywords = Object.keys(metadata);
|
||||
|
||||
let tagIndent = '';
|
||||
|
||||
for (let i = 0; i < depth; i++) {
|
||||
tagIndent += '>';
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
tagIndent += ' '; // If indented, add a space after the indents.
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
for (let i = 0; i < keywords.length; i++) {
|
||||
let keyword = keywords[i];
|
||||
@@ -245,7 +272,6 @@ function getRows(metadata, depth = 0) {
|
||||
|
||||
const sequence = {
|
||||
tag: tagInfo.tag,
|
||||
tagIndent,
|
||||
vr: tagInfo.vr,
|
||||
keyword,
|
||||
values: [],
|
||||
@@ -311,7 +337,6 @@ function getRows(metadata, depth = 0) {
|
||||
if (tagInfo) {
|
||||
rows.push({
|
||||
tag: tagInfo.tag,
|
||||
tagIndent,
|
||||
vr: tagInfo.vr,
|
||||
keyword,
|
||||
value,
|
||||
@@ -323,7 +348,6 @@ function getRows(metadata, depth = 0) {
|
||||
const tag = `(${keyword.substring(0, 4)},${keyword.substring(4, 8)})`;
|
||||
rows.push({
|
||||
tag,
|
||||
tagIndent,
|
||||
vr: '',
|
||||
keyword: 'Private Tag',
|
||||
value,
|
||||
@@ -335,10 +359,6 @@ function getRows(metadata, depth = 0) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
function _isImageStack(displaySet) {
|
||||
return displaySet instanceof ImageSet;
|
||||
}
|
||||
|
||||
function toArray(objectOrArray) {
|
||||
return Array.isArray(objectOrArray) ? objectOrArray : [objectOrArray];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { VariableSizeList as List } from 'react-window';
|
||||
import classNames from 'classnames';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { Row } from './DicomTagBrowser';
|
||||
import { Icons } from '@ohif/ui-next';
|
||||
|
||||
const lineHeightPx = 20;
|
||||
const lineHeightClassName = `leading-[${lineHeightPx}px]`;
|
||||
@@ -12,6 +14,62 @@ const rowStyle = {
|
||||
borderBottomWidth: `${rowBottomBorderPx}px`,
|
||||
...rowVerticalPaddingStyle,
|
||||
};
|
||||
const indentationPadding = 8;
|
||||
|
||||
const RowComponent = ({
|
||||
row,
|
||||
style,
|
||||
keyPrefix,
|
||||
onToggle,
|
||||
}: {
|
||||
row: Row;
|
||||
style: any;
|
||||
keyPrefix: string;
|
||||
onToggle?: (areChildrenVisible: boolean) => void;
|
||||
}) => {
|
||||
const handleToggle = useCallback(() => {
|
||||
onToggle(!row.areChildrenVisible);
|
||||
}, [row.areChildrenVisible, onToggle]);
|
||||
|
||||
const hasChildren = row.children && row.children.length > 0;
|
||||
const isChildOrParent = hasChildren || row.depth > 0;
|
||||
const padding = indentationPadding * (1 + 2 * row.depth);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ ...style, ...rowStyle }}
|
||||
className={classNames(
|
||||
'hover:bg-secondary-main border-secondary-light flex w-full flex-row items-center break-all bg-black text-base transition duration-300',
|
||||
lineHeightClassName
|
||||
)}
|
||||
key={keyPrefix}
|
||||
>
|
||||
{isChildOrParent && (
|
||||
<div style={{ paddingLeft: `${padding}px`, opacity: onToggle ? 1 : 0 }}>
|
||||
{row.areChildrenVisible ? (
|
||||
<div
|
||||
className="cursor-pointer p-1"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<Icons.ChevronDown />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="cursor-pointer p-1"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<Icons.ChevronRight />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="w-4/24 px-3">{row.tag}</div>
|
||||
<div className="w-2/24 px-3">{row.valueRepresentation}</div>
|
||||
<div className="w-6/24 px-3">{row.keyword}</div>
|
||||
<div className="w-5/24 grow px-3">{row.value}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function ColumnHeaders({ tagRef, vrRef, keywordRef, valueRef }) {
|
||||
return (
|
||||
@@ -56,8 +114,7 @@ function ColumnHeaders({ tagRef, vrRef, keywordRef, valueRef }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DicomTagTable({ rows }) {
|
||||
function DicomTagTable({ rows }: { rows: Row[] }) {
|
||||
const listRef = useRef();
|
||||
const canvasRef = useRef();
|
||||
|
||||
@@ -65,6 +122,7 @@ function DicomTagTable({ rows }) {
|
||||
const [vrHeaderElem, setVrHeaderElem] = useState(null);
|
||||
const [keywordHeaderElem, setKeywordHeaderElem] = useState(null);
|
||||
const [valueHeaderElem, setValueHeaderElem] = useState(null);
|
||||
const [internalRows, setInternalRows] = useState(rows);
|
||||
|
||||
// Here the refs are inturn stored in state to trigger a render of the table.
|
||||
// This virtualized table does NOT render until the header is rendered because the header column widths are used to determine the row heights in the table.
|
||||
@@ -90,6 +148,14 @@ function DicomTagTable({ rows }) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setInternalRows(rows);
|
||||
}, [rows]);
|
||||
|
||||
const visibleRows = useMemo(() => {
|
||||
return internalRows.filter(row => row.isVisible);
|
||||
}, [internalRows]);
|
||||
|
||||
/**
|
||||
* When new rows are set, scroll to the top and reset the virtualization.
|
||||
*/
|
||||
@@ -116,42 +182,8 @@ function DicomTagTable({ rows }) {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const Row = useCallback(
|
||||
({ index, style }) => {
|
||||
const row = rows[index];
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ ...style, ...rowStyle }}
|
||||
className={classNames(
|
||||
'hover:bg-secondary-main border-secondary-light flex w-full flex-row items-center break-all bg-black text-base transition duration-300',
|
||||
lineHeightClassName
|
||||
)}
|
||||
key={`DICOMTagRow-${index}`}
|
||||
>
|
||||
<div className="w-4/24 px-3">{row[0]}</div>
|
||||
<div className="w-2/24 px-3">{row[1]}</div>
|
||||
<div className="w-6/24 px-3">{row[2]}</div>
|
||||
<div className="w-5/24 grow px-3">{row[3]}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[rows]
|
||||
);
|
||||
|
||||
/**
|
||||
* Whenever any one of the column headers is set, then the header is rendered.
|
||||
* Here we chose the tag header.
|
||||
*/
|
||||
const isHeaderRendered = useCallback(() => tagHeaderElem !== null, [tagHeaderElem]);
|
||||
|
||||
/**
|
||||
* Get the item/row size. We use the header column widths to calculate the various row heights.
|
||||
* @param index the row index
|
||||
* @returns the row height
|
||||
*/
|
||||
const getItemSize = useCallback(
|
||||
index => {
|
||||
const getOneRowHeight = useCallback(
|
||||
row => {
|
||||
const headerWidths = [
|
||||
tagHeaderElem.offsetWidth,
|
||||
vrHeaderElem.offsetWidth,
|
||||
@@ -162,17 +194,79 @@ function DicomTagTable({ rows }) {
|
||||
const context = canvasRef.current.getContext('2d');
|
||||
context.font = getComputedStyle(canvasRef.current).font;
|
||||
|
||||
return rows[index]
|
||||
.map((colText, index) => {
|
||||
const propertiesToCheck = ['tag', 'valueRepresentation', 'keyword', 'value'];
|
||||
|
||||
return Object.entries(row)
|
||||
.filter(([key]) => propertiesToCheck.includes(key))
|
||||
.map(([, colText], index) => {
|
||||
const colOneLineWidth = context.measureText(colText).width;
|
||||
const numLines = Math.ceil(colOneLineWidth / headerWidths[index]);
|
||||
return numLines * lineHeightPx + 2 * rowVerticalPaddingPx + rowBottomBorderPx;
|
||||
})
|
||||
.reduce((maxHeight, colHeight) => Math.max(maxHeight, colHeight));
|
||||
.reduce((maxHeight, colHeight) => Math.max(maxHeight, colHeight), 0);
|
||||
},
|
||||
[rows, keywordHeaderElem, tagHeaderElem, valueHeaderElem, vrHeaderElem]
|
||||
[keywordHeaderElem, tagHeaderElem, valueHeaderElem, vrHeaderElem]
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the item/row size. We use the header column widths to calculate the various row heights.
|
||||
* @param index the row index
|
||||
* @returns the row height
|
||||
*/
|
||||
const getItemSize = useCallback(
|
||||
rows => index => {
|
||||
const row = rows[index];
|
||||
const height = getOneRowHeight(row);
|
||||
return height;
|
||||
},
|
||||
[getOneRowHeight]
|
||||
);
|
||||
|
||||
const onToggle = useCallback(
|
||||
sourceRow => {
|
||||
if (!sourceRow.children) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return areChildrenVisible => {
|
||||
const newInternalRows = internalRows.map(internalRow => {
|
||||
if (sourceRow.uid === internalRow.uid) {
|
||||
return { ...internalRow, areChildrenVisible };
|
||||
}
|
||||
if (sourceRow.children.includes(internalRow.uid)) {
|
||||
return { ...internalRow, isVisible: areChildrenVisible, areChildrenVisible };
|
||||
}
|
||||
return internalRow;
|
||||
});
|
||||
setInternalRows(newInternalRows);
|
||||
};
|
||||
},
|
||||
[internalRows]
|
||||
);
|
||||
|
||||
const getRowComponent = useCallback(
|
||||
({ rows }: { rows: Row[] }) =>
|
||||
function RowList({ index, style }) {
|
||||
const row = useMemo(() => rows[index], [index]);
|
||||
|
||||
return (
|
||||
<RowComponent
|
||||
style={style}
|
||||
row={row}
|
||||
keyPrefix={`DICOMTagRow-${index}`}
|
||||
onToggle={onToggle(row)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[onToggle]
|
||||
);
|
||||
|
||||
/**
|
||||
* Whenever any one of the column headers is set, then the header is rendered.
|
||||
* Here we chose the tag header.
|
||||
*/
|
||||
const isHeaderRendered = useCallback(() => tagHeaderElem !== null, [tagHeaderElem]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<canvas
|
||||
@@ -194,12 +288,12 @@ function DicomTagTable({ rows }) {
|
||||
<List
|
||||
ref={listRef}
|
||||
height={500}
|
||||
itemCount={rows.length}
|
||||
itemSize={getItemSize}
|
||||
itemCount={visibleRows.length}
|
||||
itemSize={getItemSize(visibleRows)}
|
||||
width={'100%'}
|
||||
className="ohif-scrollbar"
|
||||
>
|
||||
{Row}
|
||||
{getRowComponent({ rows: visibleRows })}
|
||||
</List>
|
||||
)}
|
||||
</div>
|
||||
@@ -207,4 +301,4 @@ function DicomTagTable({ rows }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default DicomTagTable;
|
||||
export default React.memo(DicomTagTable);
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DicomMetadataStore, IWebApiDataSource } from '@ohif/core';
|
||||
import { get, uniqBy } from 'lodash';
|
||||
import get from 'lodash.get';
|
||||
import uniqBy from 'lodash.uniqby';
|
||||
import {
|
||||
MergeConfig,
|
||||
CallForAllDataSourcesAsyncOptions,
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useImageViewer } from '@ohif/ui';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { StudyBrowser } from '@ohif/ui-next';
|
||||
import { utils } from '@ohif/core';
|
||||
import { useSystem, utils } from '@ohif/core';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Separator } from '@ohif/ui-next';
|
||||
import { PanelStudyBrowserHeader } from './PanelStudyBrowserHeader';
|
||||
@@ -16,13 +16,12 @@ const { sortStudyInstances, formatDate, createStudyBrowserTabs } = utils;
|
||||
* @param {*} param0
|
||||
*/
|
||||
function PanelStudyBrowser({
|
||||
servicesManager,
|
||||
getImageSrc,
|
||||
getStudiesForPatientByMRN,
|
||||
requestDisplaySetCreationForStudy,
|
||||
dataSource,
|
||||
commandsManager,
|
||||
}: withAppTypes) {
|
||||
}) {
|
||||
const { servicesManager, commandsManager } = useSystem();
|
||||
const { hangingProtocolService, displaySetService, uiNotificationService, customizationService } =
|
||||
servicesManager.services;
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -5,6 +5,7 @@ import PanelStudyBrowser from './StudyBrowser/PanelStudyBrowser';
|
||||
import getImageSrcFromImageId from './getImageSrcFromImageId';
|
||||
import getStudiesForPatientByMRN from './getStudiesForPatientByMRN';
|
||||
import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStudy';
|
||||
import { useSystem } from '@ohif/core';
|
||||
|
||||
/**
|
||||
* Wraps the PanelStudyBrowser and provides features afforded by managers/services
|
||||
@@ -13,7 +14,8 @@ import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStu
|
||||
* @param {object} commandsManager
|
||||
* @param {object} extensionManager
|
||||
*/
|
||||
function WrappedPanelStudyBrowser({ extensionManager, servicesManager, commandsManager }) {
|
||||
function WrappedPanelStudyBrowser() {
|
||||
const { extensionManager } = useSystem();
|
||||
// TODO: This should be made available a different way; route should have
|
||||
// already determined our datasource
|
||||
const [dataSource] = extensionManager.getActiveDataSource();
|
||||
@@ -29,8 +31,6 @@ function WrappedPanelStudyBrowser({ extensionManager, servicesManager, commandsM
|
||||
|
||||
return (
|
||||
<PanelStudyBrowser
|
||||
servicesManager={servicesManager}
|
||||
commandsManager={commandsManager}
|
||||
dataSource={dataSource}
|
||||
getImageSrc={_getImageSrcFromImageId}
|
||||
getStudiesForPatientByMRN={_getStudiesForPatientByMRN}
|
||||
@@ -61,10 +61,4 @@ function _createGetImageSrcFromImageIdFn(extensionManager) {
|
||||
}
|
||||
}
|
||||
|
||||
WrappedPanelStudyBrowser.propTypes = {
|
||||
commandsManager: PropTypes.object.isRequired,
|
||||
extensionManager: PropTypes.object.isRequired,
|
||||
servicesManager: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default WrappedPanelStudyBrowser;
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ToolButton } from '@ohif/ui-next';
|
||||
|
||||
/**
|
||||
* Wraps the ToolButtonList component to handle the OHIF toolbar button structure
|
||||
* @param props - Component props
|
||||
* @returns Component
|
||||
*/
|
||||
export function ToolBoxButtonGroupWrapper({ groupId, items, onInteraction, ...props }) {
|
||||
if (!items || !groupId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-popover flex flex-row space-x-1 rounded-md px-0 py-0">
|
||||
{items.map(item => (
|
||||
<ToolButton
|
||||
{...item}
|
||||
key={item.id}
|
||||
size="small"
|
||||
className={props.disabled && 'text-primary'}
|
||||
onInteraction={() =>
|
||||
onInteraction?.({ groupId, itemId: item.id, commands: item.commands })
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ToolBoxButtonWrapper({ onInteraction, ...props }) {
|
||||
return (
|
||||
<div className="bg-popover flex flex-row rounded-md px-0 py-0">
|
||||
<ToolButton
|
||||
{...props}
|
||||
id={props.id}
|
||||
size="small"
|
||||
className={classNames(props.disabled && 'text-primary')}
|
||||
onInteraction={() => onInteraction?.({ itemId: props.id, commands: props.commands })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
ToolButtonList,
|
||||
ToolButton,
|
||||
ToolButtonListDefault,
|
||||
ToolButtonListDropDown,
|
||||
ToolButtonListItem,
|
||||
ToolButtonListDivider,
|
||||
} from '@ohif/ui-next';
|
||||
|
||||
interface ButtonItem {
|
||||
id: string;
|
||||
icon?: string;
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
isActive?: boolean;
|
||||
disabledText?: string;
|
||||
commands?: Record<string, unknown>;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface ToolButtonListWrapperProps {
|
||||
groupId: string;
|
||||
primary: ButtonItem;
|
||||
items: ButtonItem[];
|
||||
onInteraction?: (details: {
|
||||
groupId: string;
|
||||
itemId: string;
|
||||
commands?: Record<string, unknown>;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the ToolButtonList component to handle the OHIF toolbar button structure
|
||||
* @param props - Component props
|
||||
* @returns Component
|
||||
* // test
|
||||
*/
|
||||
export default function ToolButtonListWrapper({
|
||||
groupId,
|
||||
primary,
|
||||
items,
|
||||
onInteraction,
|
||||
}: ToolButtonListWrapperProps) {
|
||||
return (
|
||||
<ToolButtonList>
|
||||
<ToolButtonListDefault>
|
||||
<div
|
||||
data-cy={`${groupId}-split-button-primary`}
|
||||
data-tool={primary.id}
|
||||
data-active={primary.isActive}
|
||||
>
|
||||
<ToolButton
|
||||
{...primary}
|
||||
onInteraction={({ itemId }) =>
|
||||
onInteraction?.({ groupId, itemId, commands: primary.commands })
|
||||
}
|
||||
className={primary.className}
|
||||
/>
|
||||
</div>
|
||||
</ToolButtonListDefault>
|
||||
<ToolButtonListDivider className={primary.isActive ? 'opacity-0' : 'opacity-100'} />
|
||||
<div data-cy={`${groupId}-split-button-secondary`}>
|
||||
<ToolButtonListDropDown>
|
||||
{items.map(item => (
|
||||
<ToolButtonListItem
|
||||
key={item.id}
|
||||
{...item}
|
||||
data-cy={item.id}
|
||||
data-tool={item.id}
|
||||
data-active={item.isActive}
|
||||
onSelect={() =>
|
||||
onInteraction?.({ groupId, itemId: item.id, commands: item.commands })
|
||||
}
|
||||
>
|
||||
<span className="pl-1">{item.label || item.tooltip || item.id}</span>
|
||||
</ToolButtonListItem>
|
||||
))}
|
||||
</ToolButtonListDropDown>
|
||||
</div>
|
||||
</ToolButtonList>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
import React from 'react';
|
||||
import { Tooltip } from '@ohif/ui';
|
||||
import classnames from 'classnames';
|
||||
import { useToolbar } from '@ohif/core';
|
||||
|
||||
export function Toolbar({ servicesManager, buttonSection = 'primary' }) {
|
||||
@@ -15,7 +13,7 @@ export function Toolbar({ servicesManager, buttonSection = 'primary' }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{toolbarButtons.map(toolDef => {
|
||||
{toolbarButtons?.map(toolDef => {
|
||||
if (!toolDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ToolbarButton, ButtonGroup } from '@ohif/ui';
|
||||
import React, { useCallback } from 'react';
|
||||
import { ToolbarButton, ButtonGroup } from '@ohif/ui';
|
||||
|
||||
function ToolbarButtonGroupWithServices({ groupId, items, onInteraction, size }) {
|
||||
const getSplitButtonItems = useCallback(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { panelGroupDefinition } from './constants/panels';
|
||||
/**
|
||||
* Set the minimum and maximum css style width attributes for the given element.
|
||||
* The two style attributes are cleared whenever the width
|
||||
* arguments is undefined.
|
||||
* argument is undefined.
|
||||
* <p>
|
||||
* This utility is used as part of a HACK throughout the ViewerLayout component as
|
||||
* the means of restricting the side panel widths during the resizing of the
|
||||
@@ -34,7 +34,7 @@ const useResizablePanels = (
|
||||
);
|
||||
const [leftResizablePanelMinimumSize, setLeftResizablePanelMinimumSize] = useState(0);
|
||||
const [rightResizablePanelMinimumSize, setRightResizablePanelMinimumSize] = useState(0);
|
||||
const [leftResizeablePanelCollapsedSize, setLeftResizePanelCollapsedSize] = useState(0);
|
||||
const [leftResizablePanelCollapsedSize, setLeftResizePanelCollapsedSize] = useState(0);
|
||||
const [rightResizePanelCollapsedSize, setRightResizePanelCollapsedSize] = useState(0);
|
||||
|
||||
const resizablePanelGroupElemRef = useRef(null);
|
||||
@@ -44,15 +44,16 @@ const useResizablePanels = (
|
||||
const resizableRightPanelAPIRef = useRef(null);
|
||||
const isResizableHandleDraggingRef = useRef(false);
|
||||
|
||||
// The total width of both handles.
|
||||
const resizableHandlesWidth = useRef(null);
|
||||
|
||||
// This useLayoutEffect is used to...
|
||||
// - Grab a reference to the various resizable panel elements needed for
|
||||
// converting between percentages and pixels in various callbacks.
|
||||
// - Expand those panels that are initially expanded.
|
||||
useLayoutEffect(() => {
|
||||
const panelGroupElem = getPanelGroupElement(panelGroupDefinition.groupId);
|
||||
|
||||
resizablePanelGroupElemRef.current = panelGroupElem;
|
||||
const { width: panelGroupWidth } = panelGroupElem.getBoundingClientRect();
|
||||
|
||||
const leftPanelElem = getPanelElement(panelGroupDefinition.left.panelId);
|
||||
resizableLeftPanelElemRef.current = leftPanelElem;
|
||||
@@ -60,20 +61,29 @@ const useResizablePanels = (
|
||||
const rightPanelElem = getPanelElement(panelGroupDefinition.right.panelId);
|
||||
resizableRightPanelElemRef.current = rightPanelElem;
|
||||
|
||||
// Calculate and set the width of both handles combined.
|
||||
const resizeHandles = document.querySelectorAll('[data-panel-resize-handle-id]');
|
||||
resizableHandlesWidth.current = 0;
|
||||
resizeHandles.forEach(resizeHandle => {
|
||||
resizableHandlesWidth.current += resizeHandle.offsetWidth;
|
||||
});
|
||||
|
||||
// Since both resizable panels are collapsed by default (i.e. their default size is zero),
|
||||
// on the very first render check if either/both side panels should be expanded.
|
||||
// we use the initialExpandedOffsetWidth on the first render incase the panel has min width but we want the initial state to be larger than that
|
||||
|
||||
if (!leftPanelClosed) {
|
||||
const leftResizablePanelExpandedSize =
|
||||
(panelGroupDefinition.left.initialExpandedOffsetWidth / panelGroupWidth) * 100;
|
||||
const leftResizablePanelExpandedSize = getPercentageSize(
|
||||
panelGroupDefinition.left.initialExpandedOffsetWidth
|
||||
);
|
||||
resizableLeftPanelAPIRef?.current?.expand(leftResizablePanelExpandedSize);
|
||||
setMinMaxWidth(leftPanelElem, panelGroupDefinition.left.initialExpandedOffsetWidth);
|
||||
}
|
||||
|
||||
if (!rightPanelClosed) {
|
||||
const rightResizablePanelExpandedSize =
|
||||
(panelGroupDefinition.right.initialExpandedOffsetWidth / panelGroupWidth) * 100;
|
||||
const rightResizablePanelExpandedSize = getPercentageSize(
|
||||
panelGroupDefinition.right.initialExpandedOffsetWidth
|
||||
);
|
||||
resizableRightPanelAPIRef?.current?.expand(rightResizablePanelExpandedSize);
|
||||
setMinMaxWidth(rightPanelElem, panelGroupDefinition.right.initialExpandedOffsetWidth);
|
||||
}
|
||||
@@ -89,103 +99,47 @@ const useResizablePanels = (
|
||||
// values whenever the resizable panel group is resized (e.g. whenever the
|
||||
// browser window is resized).
|
||||
useLayoutEffect(() => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
|
||||
// Ensure the side panels' percentage size is in synch with the pixel width of the
|
||||
// expanded side panels. In general the two get out-of-sync during a browser
|
||||
// window resize. Note that this code is here and NOT in the ResizeObserver
|
||||
// because it has to be done AFTER the minimum percentage size for a panel is
|
||||
// updated which occurs only AFTER the render following a resize. And by virtue
|
||||
// of the dependency on the `resizablePanelDefaultSize` state, this code
|
||||
// is executed on the render following an update of the minimum percentage size
|
||||
// updated which occurs only AFTER the render following a browser window resize.
|
||||
// And by virtue of the dependency on the minimum size state variables, this code
|
||||
// is executed on the render following an update of the minimum percentage sizes
|
||||
// for a panel.
|
||||
if (!resizableLeftPanelAPIRef.current.isCollapsed()) {
|
||||
const leftSize =
|
||||
((leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize) /
|
||||
panelGroupWidth) *
|
||||
100;
|
||||
resizableLeftPanelAPIRef.current.resize(leftSize);
|
||||
if (!resizableLeftPanelAPIRef.current?.isCollapsed()) {
|
||||
const leftSize = getPercentageSize(
|
||||
leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize
|
||||
);
|
||||
resizableLeftPanelAPIRef.current?.resize(leftSize);
|
||||
}
|
||||
|
||||
if (!resizableRightPanelAPIRef.current.isCollapsed()) {
|
||||
const rightSize =
|
||||
((rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize) /
|
||||
panelGroupWidth) *
|
||||
100;
|
||||
resizableRightPanelAPIRef.current.resize(rightSize);
|
||||
if (!resizableRightPanelAPIRef?.current?.isCollapsed()) {
|
||||
const rightSize = getPercentageSize(
|
||||
rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize
|
||||
);
|
||||
resizableRightPanelAPIRef?.current?.resize(rightSize);
|
||||
}
|
||||
|
||||
// This observer kicks in when the ViewportLayout resizable panel group
|
||||
// component is resized. This typically occurs when the browser window resizes.
|
||||
const observer = new ResizeObserver(() => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
const minimumLeftSize =
|
||||
(panelGroupDefinition.left.minimumExpandedOffsetWidth / panelGroupWidth) * 100;
|
||||
const minimumRightSize =
|
||||
(panelGroupDefinition.right.minimumExpandedOffsetWidth / panelGroupWidth) * 100;
|
||||
const minimumLeftSize = getPercentageSize(
|
||||
panelGroupDefinition.left.minimumExpandedOffsetWidth
|
||||
);
|
||||
const minimumRightSize = getPercentageSize(
|
||||
panelGroupDefinition.right.minimumExpandedOffsetWidth
|
||||
);
|
||||
|
||||
// Set the new default and collapsed resizable panel sizes.
|
||||
setLeftResizablePanelMinimumSize(Math.min(50, minimumLeftSize));
|
||||
setRightResizablePanelMinimumSize(Math.min(50, minimumRightSize));
|
||||
// Set the new minimum and collapsed resizable panel sizes.
|
||||
setLeftResizablePanelMinimumSize(minimumLeftSize);
|
||||
setRightResizablePanelMinimumSize(minimumRightSize);
|
||||
setLeftResizePanelCollapsedSize(
|
||||
(panelGroupDefinition.left.collapsedOffsetWidth / panelGroupWidth) * 100
|
||||
getPercentageSize(panelGroupDefinition.left.collapsedOffsetWidth)
|
||||
);
|
||||
setRightResizePanelCollapsedSize(
|
||||
(panelGroupDefinition.right.collapsedOffsetWidth / panelGroupWidth) * 100
|
||||
getPercentageSize(panelGroupDefinition.right.collapsedOffsetWidth)
|
||||
);
|
||||
|
||||
if (
|
||||
resizableLeftPanelAPIRef.current.isCollapsed() &&
|
||||
resizableRightPanelAPIRef.current.isCollapsed()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The code that follows is to handle cases when the group panel is resized to be
|
||||
// too small to display either side panel at its current width.
|
||||
|
||||
// Determine the current widths of the two side panels.
|
||||
let leftPanelOffsetWidth = resizableLeftPanelAPIRef.current.isCollapsed()
|
||||
? panelGroupDefinition.left.collapsedOffsetWidth
|
||||
: leftPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize;
|
||||
|
||||
let rightPanelOffsetWidth = resizableRightPanelAPIRef.current.isCollapsed()
|
||||
? panelGroupDefinition.right.collapsedOffsetWidth
|
||||
: rightPanelExpandedWidth + panelGroupDefinition.shared.expandedInsideBorderSize;
|
||||
|
||||
if (
|
||||
!resizableLeftPanelAPIRef.current.isCollapsed() &&
|
||||
leftPanelOffsetWidth + rightPanelOffsetWidth > panelGroupWidth
|
||||
) {
|
||||
// There is not enough space to show both panels at their pre-resize widths.
|
||||
// Note that at this point, the viewport grid component is zero width.
|
||||
// Reduce the left panel width so that both panels might fit.
|
||||
leftPanelOffsetWidth = Math.max(
|
||||
panelGroupWidth - rightPanelOffsetWidth,
|
||||
panelGroupDefinition.left.minimumExpandedOffsetWidth
|
||||
);
|
||||
setLeftPanelExpandedWidth(
|
||||
leftPanelOffsetWidth - panelGroupDefinition.shared.expandedInsideBorderSize
|
||||
);
|
||||
setMinMaxWidth(resizableLeftPanelElemRef.current, leftPanelOffsetWidth);
|
||||
}
|
||||
|
||||
if (
|
||||
!resizableRightPanelAPIRef.current.isCollapsed() &&
|
||||
rightPanelOffsetWidth + leftPanelOffsetWidth > panelGroupWidth
|
||||
) {
|
||||
// There is not enough space to show both panels at their pre-resize widths.
|
||||
// Note that at this point, the viewport grid component is zero width.
|
||||
// Reduce the right panel width so that both panels might fit.
|
||||
rightPanelOffsetWidth = Math.max(
|
||||
panelGroupWidth - leftPanelOffsetWidth,
|
||||
panelGroupDefinition.right.minimumExpandedOffsetWidth
|
||||
);
|
||||
setRightPanelExpandedWidth(
|
||||
rightPanelOffsetWidth - panelGroupDefinition.shared.expandedInsideBorderSize
|
||||
);
|
||||
setMinMaxWidth(resizableRightPanelElemRef.current, rightPanelOffsetWidth);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(resizablePanelGroupElemRef.current);
|
||||
@@ -238,23 +192,26 @@ const useResizablePanels = (
|
||||
}, [setLeftPanelClosed]);
|
||||
|
||||
const onLeftPanelOpen = useCallback(() => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
resizableLeftPanelAPIRef?.current?.expand(
|
||||
(panelGroupDefinition.left.initialExpandedOffsetWidth / panelGroupWidth) * 100
|
||||
getPercentageSize(panelGroupDefinition.left.initialExpandedOffsetWidth)
|
||||
);
|
||||
setLeftPanelClosed(false);
|
||||
}, [setLeftPanelClosed]);
|
||||
|
||||
const onLeftPanelResize = useCallback(size => {
|
||||
if (resizableLeftPanelAPIRef.current.isCollapsed()) {
|
||||
if (!resizablePanelGroupElemRef?.current || resizableLeftPanelAPIRef.current?.isCollapsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
const newExpandedWidth =
|
||||
(size / 100) * panelGroupWidth - panelGroupDefinition.shared.expandedInsideBorderSize;
|
||||
|
||||
const newExpandedWidth = getExpandedPixelWidth(size);
|
||||
setLeftPanelExpandedWidth(newExpandedWidth);
|
||||
|
||||
if (!isResizableHandleDraggingRef.current) {
|
||||
// This typically gets executed when the left panel is expanded via one of the UI
|
||||
// buttons. It is done here instead of in the onLeftPanelOpen method
|
||||
// because here we know the size of the expanded panel.
|
||||
setMinMaxWidth(resizableLeftPanelElemRef.current, newExpandedWidth);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onRightPanelClose = useCallback(() => {
|
||||
@@ -264,25 +221,49 @@ const useResizablePanels = (
|
||||
}, [setRightPanelClosed]);
|
||||
|
||||
const onRightPanelOpen = useCallback(() => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
resizableRightPanelAPIRef?.current?.expand(
|
||||
(panelGroupDefinition.right.initialExpandedOffsetWidth / panelGroupWidth) * 100
|
||||
getPercentageSize(panelGroupDefinition.right.initialExpandedOffsetWidth)
|
||||
);
|
||||
setRightPanelClosed(false);
|
||||
}, [setRightPanelClosed]);
|
||||
|
||||
const onRightPanelResize = useCallback(size => {
|
||||
if (resizableRightPanelAPIRef?.current?.isCollapsed()) {
|
||||
if (!resizablePanelGroupElemRef?.current || resizableRightPanelAPIRef?.current?.isCollapsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current.getBoundingClientRect();
|
||||
const newExpandedWidth =
|
||||
(size / 100) * panelGroupWidth - panelGroupDefinition.shared.expandedInsideBorderSize;
|
||||
|
||||
const newExpandedWidth = getExpandedPixelWidth(size);
|
||||
setRightPanelExpandedWidth(newExpandedWidth);
|
||||
|
||||
if (!isResizableHandleDraggingRef.current) {
|
||||
// This typically gets executed when the right panel is expanded via one of the UI
|
||||
// buttons. It is done here instead of in the onRightPanelOpen method
|
||||
// because here we know the size of the expanded panel.
|
||||
setMinMaxWidth(resizableRightPanelElemRef.current, newExpandedWidth);
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Gets the percentage size corresponding to the given pixel size.
|
||||
* Note that the width attributed to the handles must be taken into account.
|
||||
*/
|
||||
const getPercentageSize = pixelSize => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current?.getBoundingClientRect();
|
||||
return (pixelSize / (panelGroupWidth - resizableHandlesWidth.current)) * 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the width in pixels for an expanded panel given its percentage size/width.
|
||||
* Note that the width attributed to the handles must be taken into account.
|
||||
*/
|
||||
const getExpandedPixelWidth = percentageSize => {
|
||||
const { width: panelGroupWidth } = resizablePanelGroupElemRef.current?.getBoundingClientRect();
|
||||
const expandedWidth =
|
||||
(percentageSize / 100) * (panelGroupWidth - resizableHandlesWidth.current) -
|
||||
panelGroupDefinition.shared.expandedInsideBorderSize;
|
||||
return expandedWidth;
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
expandedWidth: leftPanelExpandedWidth,
|
||||
@@ -308,7 +289,7 @@ const useResizablePanels = (
|
||||
minSize: leftResizablePanelMinimumSize,
|
||||
onResize: onLeftPanelResize,
|
||||
collapsible: true,
|
||||
collapsedSize: leftResizeablePanelCollapsedSize,
|
||||
collapsedSize: leftResizablePanelCollapsedSize,
|
||||
onCollapse: () => setLeftPanelClosed(true),
|
||||
onExpand: () => setLeftPanelClosed(false),
|
||||
ref: resizableLeftPanelAPIRef,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const expandedInsideBorderSize = 4;
|
||||
const expandedInsideBorderSize = 0;
|
||||
const collapsedInsideBorderSize = 4;
|
||||
const collapsedOutsideBorderSize = 8;
|
||||
const collapsedOutsideBorderSize = 4;
|
||||
const collapsedWidth = 25;
|
||||
|
||||
const rightPanelInitialExpandedWidth = 280;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { LoadingIndicatorProgress, InvestigationalUseDialog } from '@ohif/ui';
|
||||
import { InvestigationalUseDialog } from '@ohif/ui';
|
||||
import { HangingProtocolService, CommandsManager } from '@ohif/core';
|
||||
import { useAppConfig } from '@state';
|
||||
import ViewerHeader from './ViewerHeader';
|
||||
@@ -9,6 +9,8 @@ import SidePanelWithServices from '../Components/SidePanelWithServices';
|
||||
import { Onboarding, ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@ohif/ui-next';
|
||||
import useResizablePanels from './ResizablePanelsHook';
|
||||
|
||||
const resizableHandleClassName = 'mt-[1px] bg-black';
|
||||
|
||||
function ViewerLayout({
|
||||
// From Extension Module Params
|
||||
extensionManager,
|
||||
@@ -25,7 +27,7 @@ function ViewerLayout({
|
||||
}: withAppTypes): React.FunctionComponent {
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
const { panelService, hangingProtocolService } = servicesManager.services;
|
||||
const { panelService, hangingProtocolService, customizationService } = servicesManager.services;
|
||||
const [showLoadingIndicator, setShowLoadingIndicator] = useState(appConfig.showLoadingIndicator);
|
||||
|
||||
const hasPanels = useCallback(
|
||||
@@ -53,6 +55,10 @@ function ViewerLayout({
|
||||
setRightPanelClosed
|
||||
);
|
||||
|
||||
const LoadingIndicatorProgress = customizationService.getCustomization(
|
||||
'ui.loadingIndicatorProgress'
|
||||
);
|
||||
|
||||
/**
|
||||
* Set body classes (tailwindcss) that don't allow vertical
|
||||
* or horizontal overflow (no scrolling). Also guarantee window
|
||||
@@ -157,7 +163,7 @@ function ViewerLayout({
|
||||
<ResizableHandle
|
||||
onDragging={onHandleDragging}
|
||||
disabled={!leftPanelResizable}
|
||||
className="!w-0"
|
||||
className={resizableHandleClassName}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
@@ -178,7 +184,7 @@ function ViewerLayout({
|
||||
<ResizableHandle
|
||||
onDragging={onHandleDragging}
|
||||
disabled={!rightPanelResizable}
|
||||
className="!w-0"
|
||||
className={resizableHandleClassName}
|
||||
/>
|
||||
<ResizablePanel {...resizableRightPanelProps}>
|
||||
<SidePanelWithServices
|
||||
@@ -193,7 +199,7 @@ function ViewerLayout({
|
||||
</ResizablePanelGroup>
|
||||
</React.Fragment>
|
||||
</div>
|
||||
<Onboarding />
|
||||
<Onboarding tours={customizationService.getCustomization('ohif.tours')} />
|
||||
<InvestigationalUseDialog dialogConfiguration={appConfig?.investigationalUseDialog} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ContextMenu } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.contextMenu': ContextMenu,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { defaults } from '@ohif/core';
|
||||
|
||||
export default {
|
||||
'ohif.hotkeyBindings': defaults.hotkeyBindings,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LabellingFlow } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.labellingComponent': LabellingFlow,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LoadingIndicatorProgress } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.loadingIndicatorProgress': LoadingIndicatorProgress,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LoadingIndicatorTotalPercent } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.loadingIndicatorTotalPercent': LoadingIndicatorTotalPercent,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Notification } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.notificationComponent': Notification,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
customOnDropHandler: () => {
|
||||
return Promise.resolve({ handled: false });
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,210 @@
|
||||
function waitForElement(selector, maxAttempts = 20, interval = 25) {
|
||||
return new Promise(resolve => {
|
||||
let attempts = 0;
|
||||
|
||||
const checkForElement = setInterval(() => {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (element || attempts >= maxAttempts) {
|
||||
clearInterval(checkForElement);
|
||||
resolve();
|
||||
}
|
||||
|
||||
attempts++;
|
||||
}, interval);
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
'ohif.tours': [
|
||||
{
|
||||
id: 'basicViewerTour',
|
||||
route: '/viewer',
|
||||
steps: [
|
||||
{
|
||||
id: 'scroll',
|
||||
title: 'Scrolling Through Images',
|
||||
text: 'You can scroll through the images using the mouse wheel or scrollbar.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'top',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '.cornerstone-viewport-element',
|
||||
event: 'CORNERSTONE_TOOLS_MOUSE_WHEEL',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'zoom',
|
||||
title: 'Zooming In and Out',
|
||||
text: 'You can zoom the images using the right click.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'left',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '.cornerstone-viewport-element',
|
||||
event: 'CORNERSTONE_TOOLS_MOUSE_UP',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'pan',
|
||||
title: 'Panning the Image',
|
||||
text: 'You can pan the images using the middle click.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'top',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '.cornerstone-viewport-element',
|
||||
event: 'CORNERSTONE_TOOLS_MOUSE_UP',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'windowing',
|
||||
title: 'Adjusting Window Level',
|
||||
text: 'You can modify the window level using the left click.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'left',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '.cornerstone-viewport-element',
|
||||
event: 'CORNERSTONE_TOOLS_MOUSE_UP',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'length',
|
||||
title: 'Using the Measurement Tools',
|
||||
text: 'You can measure the length of a region using the Length tool.',
|
||||
attachTo: {
|
||||
element: '[data-cy="MeasurementTools-split-button-primary"]',
|
||||
on: 'bottom',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="MeasurementTools-split-button-primary"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () =>
|
||||
waitForElement('[data-cy="MeasurementTools-split-button-primary]'),
|
||||
},
|
||||
{
|
||||
id: 'drawAnnotation',
|
||||
title: 'Drawing Length Annotations',
|
||||
text: 'Use the length tool on the viewport to measure the length of a region.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'right',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: 'body',
|
||||
event: 'event::measurement_added',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'trackMeasurement',
|
||||
title: 'Tracking Measurements in the Panel',
|
||||
text: 'Click yes to track the measurements in the measurement panel.',
|
||||
attachTo: {
|
||||
element: '[data-cy="prompt-begin-tracking-yes-btn"]',
|
||||
on: 'bottom',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="prompt-begin-tracking-yes-btn"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="prompt-begin-tracking-yes-btn"]'),
|
||||
},
|
||||
{
|
||||
id: 'openMeasurementPanel',
|
||||
title: 'Opening the Measurements Panel',
|
||||
text: 'Click the measurements button to open the measurements panel.',
|
||||
attachTo: {
|
||||
element: '#trackedMeasurements-btn',
|
||||
on: 'left-start',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '#trackedMeasurements-btn',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('#trackedMeasurements-btn'),
|
||||
},
|
||||
{
|
||||
id: 'scrollAwayFromMeasurement',
|
||||
title: 'Scrolling Away from a Measurement',
|
||||
text: 'Scroll the images using the mouse wheel away from the measurement.',
|
||||
attachTo: {
|
||||
element: '.viewport-element',
|
||||
on: 'left',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '.cornerstone-viewport-element',
|
||||
event: 'CORNERSTONE_TOOLS_MOUSE_WHEEL',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('.viewport-element'),
|
||||
},
|
||||
{
|
||||
id: 'jumpToMeasurement',
|
||||
title: 'Jumping to Measurements in the Panel',
|
||||
text: 'Click the measurement in the measurement panel to jump to it.',
|
||||
attachTo: {
|
||||
element: '[data-cy="data-row"]',
|
||||
on: 'left-start',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="data-row"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="data-row"]'),
|
||||
},
|
||||
{
|
||||
id: 'changeLayout',
|
||||
title: 'Changing Layout',
|
||||
text: 'You can change the layout of the viewer using the layout button.',
|
||||
attachTo: {
|
||||
element: '[data-cy="Layout"]',
|
||||
on: 'bottom',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="Layout"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="Layout"]'),
|
||||
},
|
||||
{
|
||||
id: 'selectLayout',
|
||||
title: 'Selecting the MPR Layout',
|
||||
text: 'Select the MPR layout to view the images in MPR mode.',
|
||||
attachTo: {
|
||||
element: '[data-cy="MPR"]',
|
||||
on: 'left-start',
|
||||
},
|
||||
advanceOn: {
|
||||
selector: '[data-cy="MPR"]',
|
||||
event: 'click',
|
||||
},
|
||||
beforeShowPromise: () => waitForElement('[data-cy="MPR"]'),
|
||||
},
|
||||
],
|
||||
tourOptions: {
|
||||
useModalOverlay: true,
|
||||
defaultStepOptions: {
|
||||
buttons: [
|
||||
{
|
||||
text: 'Skip all',
|
||||
action() {
|
||||
this.complete();
|
||||
},
|
||||
secondary: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ProgressLoadingBar } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.progressLoadingBar': ProgressLoadingBar,
|
||||
};
|
||||
@@ -8,7 +8,11 @@ export default {
|
||||
id: 'tagBrowser',
|
||||
label: 'Tag Browser',
|
||||
iconName: 'DicomTagBrowser',
|
||||
commands: 'openDICOMTagViewer',
|
||||
onClick: ({ commandsManager, displaySetInstanceUID }: withAppTypes) => {
|
||||
commandsManager.runCommand('openDICOMTagViewer', {
|
||||
displaySetInstanceUID,
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
'studyBrowser.sortFunctions': [
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ViewportActionCorners } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'ui.viewportActionCorner': ViewportActionCorners,
|
||||
};
|
||||
@@ -6,11 +6,20 @@ import customRoutesCustomization from './customizations/customRoutesCustomizatio
|
||||
import studyBrowserCustomization from './customizations/studyBrowserCustomization';
|
||||
import overlayItemCustomization from './customizations/overlayItemCustomization';
|
||||
import contextMenuCustomization from './customizations/contextMenuCustomization';
|
||||
import contextMenuUICustomization from './customizations/contextMenuUICustomization';
|
||||
import menuContentCustomization from './customizations/menuContentCustomization';
|
||||
import getDataSourceConfigurationCustomization from './customizations/dataSourceConfigurationCustomization';
|
||||
import progressDropdownCustomization from './customizations/progressDropdownCustomization';
|
||||
import sortingCriteriaCustomization from './customizations/sortingCriteriaCustomization';
|
||||
|
||||
import onDropHandlerCustomization from './customizations/onDropHandlerCustomization';
|
||||
import loadingIndicatorProgressCustomization from './customizations/loadingIndicatorProgressCustomization';
|
||||
import loadingIndicatorTotalPercentCustomization from './customizations/loadingIndicatorTotalPercentCustomization';
|
||||
import progressLoadingBarCustomization from './customizations/progressLoadingBarCustomization';
|
||||
import viewportActionCornersCustomization from './customizations/viewportActionCornersCustomization';
|
||||
import labellingFlowCustomization from './customizations/labellingFlowCustomization';
|
||||
import viewportNotificationCustomization from './customizations/notificationCustomization';
|
||||
import hotkeyBindingsCustomization from './customizations/hotkeyBindingsCustomization';
|
||||
import onboardingCustomization from './customizations/onboardingCustomization';
|
||||
/**
|
||||
*
|
||||
* Note: this is an example of how the customization module can be used
|
||||
@@ -46,6 +55,16 @@ export default function getCustomizationModule({ servicesManager, extensionManag
|
||||
...progressDropdownCustomization,
|
||||
...sortingCriteriaCustomization,
|
||||
...defaultContextMenuCustomization,
|
||||
...onDropHandlerCustomization,
|
||||
...loadingIndicatorProgressCustomization,
|
||||
...loadingIndicatorTotalPercentCustomization,
|
||||
...progressLoadingBarCustomization,
|
||||
...viewportActionCornersCustomization,
|
||||
...labellingFlowCustomization,
|
||||
...contextMenuUICustomization,
|
||||
...viewportNotificationCustomization,
|
||||
...hotkeyBindingsCustomization,
|
||||
...onboardingCustomization,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,42 +1,61 @@
|
||||
import ToolbarDivider from './Toolbar/ToolbarDivider';
|
||||
import { ToolbarButton as ToolbarButtonLegacy } from '@ohif/ui';
|
||||
import { ToolButton, utils } from '@ohif/ui-next';
|
||||
|
||||
import ToolbarLayoutSelectorWithServices from './Toolbar/ToolbarLayoutSelector';
|
||||
import ToolbarSplitButtonWithServices from './Toolbar/ToolbarSplitButtonWithServices';
|
||||
import ToolbarButtonGroupWithServices from './Toolbar/ToolbarButtonGroupWithServices';
|
||||
import { ToolbarButton } from '@ohif/ui';
|
||||
|
||||
// legacy
|
||||
import ToolbarDividerLegacy from './Toolbar/ToolbarDivider';
|
||||
import ToolbarSplitButtonWithServicesLegacy from './Toolbar/ToolbarSplitButtonWithServices';
|
||||
import ToolbarButtonGroupWithServicesLegacy from './Toolbar/ToolbarButtonGroupWithServices';
|
||||
import { ProgressDropdownWithService } from './Components/ProgressDropdownWithService';
|
||||
|
||||
const getClassName = isToggled => {
|
||||
return {
|
||||
className: isToggled
|
||||
? '!text-primary-active'
|
||||
: '!text-common-bright hover:!bg-primary-dark hover:text-primary-light',
|
||||
};
|
||||
};
|
||||
// new
|
||||
import ToolButtonListWrapper from './Toolbar/ToolButtonListWrapper';
|
||||
import { ToolBoxButtonGroupWrapper, ToolBoxButtonWrapper } from './Toolbar/ToolBoxWrapper';
|
||||
|
||||
export default function getToolbarModule({ commandsManager, servicesManager }: withAppTypes) {
|
||||
const { cineService } = servicesManager.services;
|
||||
return [
|
||||
// new
|
||||
{
|
||||
name: 'ohif.toolButton',
|
||||
defaultComponent: ToolButton,
|
||||
},
|
||||
{
|
||||
name: 'ohif.toolButtonList',
|
||||
defaultComponent: ToolButtonListWrapper,
|
||||
},
|
||||
{
|
||||
name: 'ohif.toolBoxButtonGroup',
|
||||
defaultComponent: ToolBoxButtonGroupWrapper,
|
||||
},
|
||||
{
|
||||
name: 'ohif.toolBoxButton',
|
||||
defaultComponent: ToolBoxButtonWrapper,
|
||||
},
|
||||
// legacy
|
||||
{
|
||||
name: 'ohif.radioGroup',
|
||||
defaultComponent: ToolbarButton,
|
||||
defaultComponent: ToolbarButtonLegacy,
|
||||
},
|
||||
{
|
||||
name: 'ohif.buttonGroup',
|
||||
defaultComponent: ToolbarButtonGroupWithServicesLegacy,
|
||||
},
|
||||
{
|
||||
name: 'ohif.divider',
|
||||
defaultComponent: ToolbarDivider,
|
||||
defaultComponent: ToolbarDividerLegacy,
|
||||
},
|
||||
{
|
||||
name: 'ohif.splitButton',
|
||||
defaultComponent: ToolbarSplitButtonWithServices,
|
||||
defaultComponent: ToolbarSplitButtonWithServicesLegacy,
|
||||
},
|
||||
// others
|
||||
{
|
||||
name: 'ohif.layoutSelector',
|
||||
defaultComponent: props =>
|
||||
ToolbarLayoutSelectorWithServices({ ...props, commandsManager, servicesManager }),
|
||||
},
|
||||
{
|
||||
name: 'ohif.buttonGroup',
|
||||
defaultComponent: ToolbarButtonGroupWithServices,
|
||||
},
|
||||
{
|
||||
name: 'ohif.progressDropdown',
|
||||
defaultComponent: ProgressDropdownWithService,
|
||||
@@ -66,7 +85,9 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
||||
name: 'evaluate.cine',
|
||||
evaluate: () => {
|
||||
const isToggled = cineService.getState().isCineEnabled;
|
||||
return getClassName(isToggled);
|
||||
return {
|
||||
className: utils.getToggledClassName(isToggled),
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -13,9 +13,8 @@ function usePatientInfo(servicesManager: AppTypes.ServicesManager) {
|
||||
PatientDOB: '',
|
||||
});
|
||||
const [isMixedPatients, setIsMixedPatients] = useState(false);
|
||||
const displaySets = displaySetService.getActiveDisplaySets();
|
||||
|
||||
const checkMixedPatients = PatientID => {
|
||||
const checkMixedPatients = (PatientID: string) => {
|
||||
const displaySets = displaySetService.getActiveDisplaySets();
|
||||
let isMixedPatients = false;
|
||||
displaySets.forEach(displaySet => {
|
||||
@@ -30,8 +29,11 @@ function usePatientInfo(servicesManager: AppTypes.ServicesManager) {
|
||||
setIsMixedPatients(isMixedPatients);
|
||||
};
|
||||
|
||||
const updatePatientInfo = () => {
|
||||
const displaySet = displaySets[0];
|
||||
const updatePatientInfo = ({ displaySetsAdded }) => {
|
||||
if (!displaySetsAdded.length) {
|
||||
return;
|
||||
}
|
||||
const displaySet = displaySetsAdded[0];
|
||||
const instance = displaySet?.instances?.[0] || displaySet?.instance;
|
||||
if (!instance) {
|
||||
return;
|
||||
@@ -39,7 +41,7 @@ function usePatientInfo(servicesManager: AppTypes.ServicesManager) {
|
||||
|
||||
setPatientInfo({
|
||||
PatientID: instance.PatientID || null,
|
||||
PatientName: instance.PatientName ? formatPN(instance.PatientName ) : null,
|
||||
PatientName: instance.PatientName ? formatPN(instance.PatientName) : null,
|
||||
PatientSex: instance.PatientSex || null,
|
||||
PatientDOB: formatDate(instance.PatientBirthDate) || null,
|
||||
});
|
||||
@@ -49,15 +51,11 @@ function usePatientInfo(servicesManager: AppTypes.ServicesManager) {
|
||||
useEffect(() => {
|
||||
const subscription = displaySetService.subscribe(
|
||||
displaySetService.EVENTS.DISPLAY_SETS_ADDED,
|
||||
() => updatePatientInfo()
|
||||
props => updatePatientInfo(props)
|
||||
);
|
||||
return () => subscription.unsubscribe();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
updatePatientInfo();
|
||||
}, [displaySets]);
|
||||
|
||||
return { patientInfo, isMixedPatients };
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import { PanelStudyBrowserHeader } from './Panels/StudyBrowser/PanelStudyBrowser
|
||||
import * as utils from './utils';
|
||||
import MoreDropdownMenu from './Components/MoreDropdownMenu';
|
||||
import requestDisplaySetCreationForStudy from './Panels/requestDisplaySetCreationForStudy';
|
||||
|
||||
const defaultExtension: Types.Extensions.Extension = {
|
||||
/**
|
||||
* Only required property. Should be a unique value across all extensions.
|
||||
|
||||
@@ -89,7 +89,13 @@ export function callInputDialog(
|
||||
}
|
||||
}
|
||||
|
||||
export function callLabelAutocompleteDialog(uiDialogService, callback, dialogConfig, labelConfig) {
|
||||
export function callLabelAutocompleteDialog(
|
||||
uiDialogService,
|
||||
callback,
|
||||
dialogConfig,
|
||||
labelConfig,
|
||||
renderContent = LabellingFlow
|
||||
) {
|
||||
const exclusive = labelConfig ? labelConfig.exclusive : false;
|
||||
const dropDownItems = labelConfig ? labelConfig.items : [];
|
||||
|
||||
@@ -112,7 +118,7 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon
|
||||
centralize: true,
|
||||
isDraggable: false,
|
||||
showOverlay: true,
|
||||
content: LabellingFlow,
|
||||
content: renderContent,
|
||||
contentProps: {
|
||||
labellingDoneCallback: labellingDoneCallback,
|
||||
measurementData: { label: '' },
|
||||
@@ -123,7 +129,12 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon
|
||||
});
|
||||
}
|
||||
|
||||
export function showLabelAnnotationPopup(measurement, uiDialogService, labelConfig) {
|
||||
export function showLabelAnnotationPopup(
|
||||
measurement,
|
||||
uiDialogService,
|
||||
labelConfig,
|
||||
renderContent = LabellingFlow
|
||||
) {
|
||||
const exclusive = labelConfig ? labelConfig.exclusive : false;
|
||||
const dropDownItems = labelConfig ? labelConfig.items : [];
|
||||
return new Promise<Map<any, any>>((resolve, reject) => {
|
||||
@@ -139,7 +150,7 @@ export function showLabelAnnotationPopup(measurement, uiDialogService, labelConf
|
||||
id: 'select-annotation',
|
||||
isDraggable: false,
|
||||
showOverlay: true,
|
||||
content: LabellingFlow,
|
||||
content: renderContent,
|
||||
defaultPosition: {
|
||||
x: window.innerWidth / 2,
|
||||
y: window.innerHeight / 2,
|
||||
|
||||
@@ -1,30 +1,42 @@
|
||||
import { showLabelAnnotationPopup } from './callInputDialog';
|
||||
|
||||
function promptLabelAnnotation({ servicesManager }, ctx, evt) {
|
||||
const { measurementService, customizationService } = servicesManager.services;
|
||||
const { viewportId, StudyInstanceUID, SeriesInstanceUID, measurementId } = evt;
|
||||
const { measurementService, customizationService, toolGroupService } = servicesManager.services;
|
||||
const { viewportId, StudyInstanceUID, SeriesInstanceUID, measurementId, toolName } = evt;
|
||||
return new Promise(async function (resolve) {
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(measurementId);
|
||||
const value = await showLabelAnnotationPopup(
|
||||
measurement,
|
||||
servicesManager.services.uiDialogService,
|
||||
labelConfig
|
||||
);
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
const activeToolOptions = toolGroup.getToolConfiguration(toolName);
|
||||
if(activeToolOptions.getTextCallback) {
|
||||
resolve({
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportId,
|
||||
})
|
||||
} else {
|
||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(measurementId);
|
||||
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
||||
const value = await showLabelAnnotationPopup(
|
||||
measurement,
|
||||
servicesManager.services.uiDialogService,
|
||||
labelConfig,
|
||||
renderContent
|
||||
);
|
||||
|
||||
measurementService.update(
|
||||
measurementId,
|
||||
{
|
||||
...value,
|
||||
},
|
||||
true
|
||||
);
|
||||
measurementService.update(
|
||||
measurementId,
|
||||
{
|
||||
...value,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
resolve({
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportId,
|
||||
});
|
||||
resolve({
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
viewportId,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ export default function areAllImagePositionsEqual(instances: Array<any>): boolea
|
||||
const firstImagePositionPatient = toNumber(instances[0].ImagePositionPatient);
|
||||
const lastIpp = toNumber(instances[instances.length - 1].ImagePositionPatient);
|
||||
|
||||
if (!firstImagePositionPatient || !lastIpp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const averageSpacingBetweenFrames =
|
||||
_getPerpendicularDistance(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
||||
|
||||
|
||||
@@ -3,6 +3,298 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* lodash dependencies ([#4791](https://github.com/OHIF/Viewers/issues/4791)) ([4e16099](https://github.com/OHIF/Viewers/commit/4e16099ad3ab777b09f6ac8f181025cfd656ab6b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add viewport overlays to microscopy mode ([#4776](https://github.com/OHIF/Viewers/issues/4776)) ([084a10f](https://github.com/OHIF/Viewers/commit/084a10f7835acab6a851922850c474bc9c7b864b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Address 3D reconstruction and Android compatibility issues and clean up 4D data mode ([#4762](https://github.com/OHIF/Viewers/issues/4762)) ([149d6d0](https://github.com/OHIF/Viewers/commit/149d6d049cd333b9e5846576b403ff387558a66f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add customization support for more UI components ([#4634](https://github.com/OHIF/Viewers/issues/4634)) ([f15eb44](https://github.com/OHIF/Viewers/commit/f15eb44b4cf49de1b73a22512571cec02effaef3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-microscopy",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "OHIF extension for DICOM microscopy",
|
||||
"author": "Bill Wallace, md-prog",
|
||||
"license": "MIT",
|
||||
@@ -30,10 +30,10 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/extension-default": "3.10.0-beta.77",
|
||||
"@ohif/i18n": "3.10.0-beta.77",
|
||||
"@ohif/ui": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/extension-default": "3.10.0-beta.112",
|
||||
"@ohif/i18n": "3.10.0-beta.112",
|
||||
"@ohif/ui": "3.10.0-beta.112",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@@ -47,6 +47,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||
"colormap": "^2.3",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"mathjs": "^12.4.2"
|
||||
}
|
||||
}
|
||||
@@ -1,314 +1,258 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LoadingIndicatorProgress } from '@ohif/ui';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { cleanDenaturalizedDataset } from '@ohif/extension-default';
|
||||
|
||||
import './DicomMicroscopyViewport.css';
|
||||
import ViewportOverlay from './components/ViewportOverlay';
|
||||
import getDicomWebClient from './utils/dicomWebClient';
|
||||
import dcmjs from 'dcmjs';
|
||||
import MicroscopyService from './services/MicroscopyService';
|
||||
import { useSystem } from '@ohif/core';
|
||||
|
||||
class DicomMicroscopyViewport extends Component {
|
||||
state = {
|
||||
error: null as any,
|
||||
isLoaded: false,
|
||||
};
|
||||
function DicomMicroscopyViewport({
|
||||
activeViewportId,
|
||||
setViewportActive,
|
||||
displaySets,
|
||||
viewportId,
|
||||
dataSource,
|
||||
resizeRef,
|
||||
}: {
|
||||
activeViewportId: string;
|
||||
setViewportActive: Function;
|
||||
displaySets: any[];
|
||||
viewportId: string;
|
||||
dataSource: any;
|
||||
resizeRef: any;
|
||||
}) {
|
||||
const { servicesManager, extensionManager } = useSystem();
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [viewer, setViewer] = useState(null);
|
||||
const [managedViewer, setManagedViewer] = useState(null);
|
||||
const overlayElement = useRef();
|
||||
const container = useRef();
|
||||
const { microscopyService, customizationService } = servicesManager.services;
|
||||
|
||||
microscopyService: MicroscopyService;
|
||||
viewer: any = null; // dicom-microscopy-viewer instance
|
||||
managedViewer: any = null; // managed wrapper of microscopy-dicom extension
|
||||
|
||||
container = React.createRef();
|
||||
overlayElement = React.createRef();
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
const { microscopyService } = this.props.servicesManager.services;
|
||||
this.microscopyService = microscopyService;
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
activeViewportId: PropTypes.string,
|
||||
setViewportActive: PropTypes.func,
|
||||
|
||||
// props from OHIF Viewport Grid
|
||||
displaySets: PropTypes.array,
|
||||
viewportId: PropTypes.string,
|
||||
viewportLabel: PropTypes.string,
|
||||
dataSource: PropTypes.object,
|
||||
viewportOptions: PropTypes.object,
|
||||
displaySetOptions: PropTypes.array,
|
||||
|
||||
// other props from wrapping component
|
||||
servicesManager: PropTypes.object,
|
||||
extensionManager: PropTypes.object,
|
||||
commandsManager: PropTypes.object,
|
||||
resizeRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the nearest ROI from the mouse click point
|
||||
*
|
||||
* @param event
|
||||
* @param autoselect
|
||||
* @returns
|
||||
*/
|
||||
getNearbyROI(event: Event, autoselect = true) {
|
||||
const symbols = Object.getOwnPropertySymbols(this.viewer);
|
||||
const _drawingSource = symbols.find(p => p.description === 'drawingSource');
|
||||
const _pyramid = symbols.find(p => p.description === 'pyramid');
|
||||
const _map = symbols.find(p => p.description === 'map');
|
||||
const _affine = symbols.find(p => p.description === 'affine');
|
||||
|
||||
const feature = this.viewer[_drawingSource].getClosestFeatureToCoordinate(
|
||||
this.viewer[_map].getEventCoordinate(event)
|
||||
);
|
||||
|
||||
if (!feature) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const roiAnnotation = this.viewer._getROIFromFeature(
|
||||
feature,
|
||||
this.viewer[_pyramid].metadata,
|
||||
this.viewer[_affine]
|
||||
);
|
||||
if (roiAnnotation && autoselect) {
|
||||
this.microscopyService.selectAnnotation(roiAnnotation);
|
||||
}
|
||||
return roiAnnotation;
|
||||
}
|
||||
const overlayData = customizationService.getCustomization('microscopyViewport.overlay');
|
||||
|
||||
// install the microscopy renderer into the web page.
|
||||
// you should only do this once.
|
||||
async installOpenLayersRenderer(container, displaySet) {
|
||||
const loadViewer = async metadata => {
|
||||
const dicomMicroscopyModule = await this.microscopyService.importDicomMicroscopyViewer();
|
||||
const { viewer: DicomMicroscopyViewer, metadata: metadataUtils } = dicomMicroscopyModule;
|
||||
const installOpenLayersRenderer = useCallback(
|
||||
async (container, displaySet) => {
|
||||
const loadViewer = async metadata => {
|
||||
const dicomMicroscopyModule = await microscopyService.importDicomMicroscopyViewer();
|
||||
const { viewer: DicomMicroscopyViewer, metadata: metadataUtils } = dicomMicroscopyModule;
|
||||
|
||||
const microscopyViewer = DicomMicroscopyViewer.VolumeImageViewer;
|
||||
const microscopyViewer = DicomMicroscopyViewer.VolumeImageViewer;
|
||||
|
||||
const client = getDicomWebClient({
|
||||
extensionManager: this.props.extensionManager,
|
||||
servicesManager: this.props.servicesManager,
|
||||
});
|
||||
|
||||
// Parse, format, and filter metadata
|
||||
const volumeImages: any[] = [];
|
||||
|
||||
/**
|
||||
* This block of code is the original way of loading DICOM into dicom-microscopy-viewer
|
||||
* as in their documentation.
|
||||
* But we have the metadata already loaded by our loaders.
|
||||
* As the metadata for microscopy DIOM files tends to be big and we don't
|
||||
* want to double load it, below we have the mechanism to reconstruct the
|
||||
* DICOM JSON structure (denaturalized) from naturalized metadata.
|
||||
* (NOTE: Our loaders cache only naturalized metadata, not the denaturalized.)
|
||||
*/
|
||||
// {
|
||||
// const retrieveOptions = {
|
||||
// studyInstanceUID: metadata[0].StudyInstanceUID,
|
||||
// seriesInstanceUID: metadata[0].SeriesInstanceUID,
|
||||
// };
|
||||
// metadata = await client.retrieveSeriesMetadata(retrieveOptions);
|
||||
// // Parse, format, and filter metadata
|
||||
// metadata.forEach(m => {
|
||||
// if (
|
||||
// volumeImages.length > 0 &&
|
||||
// m['00200052'].Value[0] != volumeImages[0].FrameOfReferenceUID
|
||||
// ) {
|
||||
// console.warn(
|
||||
// 'Expected FrameOfReferenceUID of difference instances within a series to be the same, found multiple different values',
|
||||
// m['00200052'].Value[0]
|
||||
// );
|
||||
// m['00200052'].Value[0] = volumeImages[0].FrameOfReferenceUID;
|
||||
// }
|
||||
// NOTE: depending on different data source, image.ImageType sometimes
|
||||
// is a string, not a string array.
|
||||
// m['00080008'] = transformImageTypeUnnaturalized(m['00080008']);
|
||||
|
||||
// const image = new metadataUtils.VLWholeSlideMicroscopyImage({
|
||||
// metadata: m,
|
||||
// });
|
||||
// const imageFlavor = image.ImageType[2];
|
||||
// if (imageFlavor === 'VOLUME' || imageFlavor === 'THUMBNAIL') {
|
||||
// volumeImages.push(image);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
metadata.forEach(m => {
|
||||
// NOTE: depending on different data source, image.ImageType sometimes
|
||||
// is a string, not a string array.
|
||||
m.ImageType = typeof m.ImageType === 'string' ? m.ImageType.split('\\') : m.ImageType;
|
||||
|
||||
const inst = cleanDenaturalizedDataset(
|
||||
dcmjs.data.DicomMetaDictionary.denaturalizeDataset(m),
|
||||
{
|
||||
StudyInstanceUID: m.StudyInstanceUID,
|
||||
SeriesInstanceUID: m.SeriesInstanceUID,
|
||||
dataSourceConfig: this.props.dataSource.getConfig(),
|
||||
}
|
||||
);
|
||||
if (!inst['00480105']) {
|
||||
// Optical Path Sequence, no OpticalPathIdentifier?
|
||||
// NOTE: this is actually a not-well formatted DICOM VL Whole Slide Microscopy Image.
|
||||
inst['00480105'] = {
|
||||
vr: 'SQ',
|
||||
Value: [
|
||||
{
|
||||
'00480106': {
|
||||
vr: 'SH',
|
||||
Value: ['1'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const image = new metadataUtils.VLWholeSlideMicroscopyImage({
|
||||
metadata: inst,
|
||||
const client = getDicomWebClient({
|
||||
extensionManager,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
const imageFlavor = image.ImageType[2];
|
||||
if (imageFlavor === 'VOLUME' || imageFlavor === 'THUMBNAIL') {
|
||||
volumeImages.push(image);
|
||||
}
|
||||
});
|
||||
// Parse, format, and filter metadata
|
||||
const volumeImages: any[] = [];
|
||||
|
||||
// format metadata for microscopy-viewer
|
||||
const options = {
|
||||
client,
|
||||
metadata: volumeImages,
|
||||
retrieveRendered: false,
|
||||
controls: ['overview', 'position'],
|
||||
/**
|
||||
* This block of code is the original way of loading DICOM into dicom-microscopy-viewer
|
||||
* as in their documentation.
|
||||
* But we have the metadata already loaded by our loaders.
|
||||
* As the metadata for microscopy DIOM files tends to be big and we don't
|
||||
* want to double load it, below we have the mechanism to reconstruct the
|
||||
* DICOM JSON structure (denaturalized) from naturalized metadata.
|
||||
* (NOTE: Our loaders cache only naturalized metadata, not the denaturalized.)
|
||||
*/
|
||||
// {
|
||||
// const retrieveOptions = {
|
||||
// studyInstanceUID: metadata[0].StudyInstanceUID,
|
||||
// seriesInstanceUID: metadata[0].SeriesInstanceUID,
|
||||
// };
|
||||
// metadata = await client.retrieveSeriesMetadata(retrieveOptions);
|
||||
// // Parse, format, and filter metadata
|
||||
// metadata.forEach(m => {
|
||||
// if (
|
||||
// volumeImages.length > 0 &&
|
||||
// m['00200052'].Value[0] != volumeImages[0].FrameOfReferenceUID
|
||||
// ) {
|
||||
// console.warn(
|
||||
// 'Expected FrameOfReferenceUID of difference instances within a series to be the same, found multiple different values',
|
||||
// m['00200052'].Value[0]
|
||||
// );
|
||||
// m['00200052'].Value[0] = volumeImages[0].FrameOfReferenceUID;
|
||||
// }
|
||||
// NOTE: depending on different data source, image.ImageType sometimes
|
||||
// is a string, not a string array.
|
||||
// m['00080008'] = transformImageTypeUnnaturalized(m['00080008']);
|
||||
|
||||
// const image = new metadataUtils.VLWholeSlideMicroscopyImage({
|
||||
// metadata: m,
|
||||
// });
|
||||
// const imageFlavor = image.ImageType[2];
|
||||
// if (imageFlavor === 'VOLUME' || imageFlavor === 'THUMBNAIL') {
|
||||
// volumeImages.push(image);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
metadata.forEach(m => {
|
||||
// NOTE: depending on different data source, image.ImageType sometimes
|
||||
// is a string, not a string array.
|
||||
m.ImageType = typeof m.ImageType === 'string' ? m.ImageType.split('\\') : m.ImageType;
|
||||
|
||||
const inst = cleanDenaturalizedDataset(
|
||||
dcmjs.data.DicomMetaDictionary.denaturalizeDataset(m),
|
||||
{
|
||||
StudyInstanceUID: m.StudyInstanceUID,
|
||||
SeriesInstanceUID: m.SeriesInstanceUID,
|
||||
dataSourceConfig: dataSource.getConfig(),
|
||||
}
|
||||
);
|
||||
if (!inst['00480105']) {
|
||||
// Optical Path Sequence, no OpticalPathIdentifier?
|
||||
// NOTE: this is actually a not-well formatted DICOM VL Whole Slide Microscopy Image.
|
||||
inst['00480105'] = {
|
||||
vr: 'SQ',
|
||||
Value: [
|
||||
{
|
||||
'00480106': {
|
||||
vr: 'SH',
|
||||
Value: ['1'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const image = new metadataUtils.VLWholeSlideMicroscopyImage({
|
||||
metadata: inst,
|
||||
});
|
||||
|
||||
const imageFlavor = image.ImageType[2];
|
||||
if (imageFlavor === 'VOLUME' || imageFlavor === 'THUMBNAIL') {
|
||||
volumeImages.push(image);
|
||||
}
|
||||
});
|
||||
|
||||
// format metadata for microscopy-viewer
|
||||
const options = {
|
||||
client,
|
||||
metadata: volumeImages,
|
||||
retrieveRendered: false,
|
||||
controls: ['overview', 'position'],
|
||||
};
|
||||
|
||||
const viewer = new microscopyViewer(options);
|
||||
|
||||
if (overlayElement && overlayElement.current && viewer.addViewportOverlay) {
|
||||
viewer.addViewportOverlay({
|
||||
element: overlayElement.current,
|
||||
coordinates: [0, 0], // TODO: dicom-microscopy-viewer documentation says this can be false to be automatically, but it is not.
|
||||
navigate: true,
|
||||
className: 'OpenLayersOverlay',
|
||||
});
|
||||
}
|
||||
|
||||
viewer.render({ container });
|
||||
|
||||
const { StudyInstanceUID, SeriesInstanceUID } = displaySet;
|
||||
|
||||
const managedViewer = microscopyService.addViewer(
|
||||
viewer,
|
||||
viewportId,
|
||||
container,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
managedViewer.addContextMenuCallback((event: Event) => {
|
||||
// TODO: refactor this after Bill's changes on ContextMenu feature get merged
|
||||
// const roiAnnotationNearBy = this.getNearbyROI(event);
|
||||
});
|
||||
|
||||
setViewer(viewer);
|
||||
setManagedViewer(managedViewer);
|
||||
};
|
||||
|
||||
this.viewer = new microscopyViewer(options);
|
||||
microscopyService.clearAnnotations();
|
||||
|
||||
if (this.overlayElement && this.overlayElement.current && this.viewer.addViewportOverlay) {
|
||||
this.viewer.addViewportOverlay({
|
||||
element: this.overlayElement.current,
|
||||
coordinates: [0, 0], // TODO: dicom-microscopy-viewer documentation says this can be false to be automatically, but it is not.
|
||||
navigate: true,
|
||||
className: 'OpenLayersOverlay',
|
||||
});
|
||||
}
|
||||
|
||||
this.viewer.render({ container });
|
||||
|
||||
const { StudyInstanceUID, SeriesInstanceUID } = displaySet;
|
||||
|
||||
this.managedViewer = this.microscopyService.addViewer(
|
||||
this.viewer,
|
||||
this.props.viewportId,
|
||||
container,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
|
||||
this.managedViewer.addContextMenuCallback((event: Event) => {
|
||||
// TODO: refactor this after Bill's changes on ContextMenu feature get merged
|
||||
// const roiAnnotationNearBy = this.getNearbyROI(event);
|
||||
});
|
||||
};
|
||||
|
||||
this.microscopyService.clearAnnotations();
|
||||
|
||||
let smDisplaySet = displaySet;
|
||||
if (displaySet.Modality === 'SR') {
|
||||
// for SR displaySet, let's load the actual image displaySet
|
||||
smDisplaySet = displaySet.getSourceDisplaySet();
|
||||
}
|
||||
console.log('Loading viewer metadata', smDisplaySet);
|
||||
|
||||
await loadViewer(smDisplaySet.others);
|
||||
|
||||
if (displaySet.Modality === 'SR') {
|
||||
displaySet.load(smDisplaySet);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { displaySets, viewportOptions } = this.props;
|
||||
// Todo-rename: this is always getting the 0
|
||||
const displaySet = displaySets[0];
|
||||
this.installOpenLayersRenderer(this.container.current, displaySet).then(() => {
|
||||
this.setState({ isLoaded: true });
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<{}>, prevState: Readonly<{}>, snapshot?: any): void {
|
||||
if (this.managedViewer && prevProps.displaySets !== this.props.displaySets) {
|
||||
const { displaySets } = this.props;
|
||||
const displaySet = displaySets[0];
|
||||
|
||||
this.microscopyService.clearAnnotations();
|
||||
|
||||
// loading SR
|
||||
let smDisplaySet = displaySet;
|
||||
if (displaySet.Modality === 'SR') {
|
||||
const referencedDisplaySet = displaySet.getSourceDisplaySet();
|
||||
displaySet.load(referencedDisplaySet);
|
||||
// for SR displaySet, let's load the actual image displaySet
|
||||
smDisplaySet = displaySet.getSourceDisplaySet();
|
||||
}
|
||||
console.log('Loading viewer metadata', smDisplaySet);
|
||||
|
||||
await loadViewer(smDisplaySet.others);
|
||||
|
||||
if (displaySet.Modality === 'SR') {
|
||||
displaySet.load(smDisplaySet);
|
||||
}
|
||||
},
|
||||
[dataSource, extensionManager, microscopyService, servicesManager, viewportId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const displaySet = displaySets[0];
|
||||
installOpenLayersRenderer(container.current, displaySet).then(() => {
|
||||
setIsLoaded(true);
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (viewer) {
|
||||
microscopyService.removeViewer(viewer);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const displaySet = displaySets[0];
|
||||
|
||||
microscopyService.clearAnnotations();
|
||||
|
||||
// loading SR
|
||||
if (displaySet.Modality === 'SR') {
|
||||
const referencedDisplaySet = displaySet.getSourceDisplaySet();
|
||||
displaySet.load(referencedDisplaySet);
|
||||
}
|
||||
}
|
||||
}, [managedViewer, displaySets, microscopyService]);
|
||||
|
||||
componentWillUnmount() {
|
||||
this.microscopyService.removeViewer(this.viewer);
|
||||
}
|
||||
const style = { width: '100%', height: '100%' };
|
||||
const displaySet = displaySets[0];
|
||||
const firstInstance = displaySet.firstInstance || displaySet.instance;
|
||||
const LoadingIndicatorProgress = customizationService.getCustomization(
|
||||
'ui.loadingIndicatorProgress'
|
||||
);
|
||||
|
||||
setViewportActiveHandler = () => {
|
||||
const { setViewportActive, viewportId, activeViewportId } = this.props;
|
||||
|
||||
if (viewportId !== activeViewportId) {
|
||||
setViewportActive(viewportId);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const style = { width: '100%', height: '100%' };
|
||||
const displaySet = this.props.displaySets[0];
|
||||
const firstInstance = displaySet.firstInstance || displaySet.instance;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={'DicomMicroscopyViewer'}
|
||||
style={style}
|
||||
onClick={this.setViewportActiveHandler}
|
||||
>
|
||||
<div style={{ ...style, display: 'none' }}>
|
||||
<div style={{ ...style }} ref={this.overlayElement}>
|
||||
<div style={{ position: 'relative', height: '100%', width: '100%' }}>
|
||||
{displaySet && firstInstance.imageId && (
|
||||
<ViewportOverlay
|
||||
displaySet={displaySet}
|
||||
instance={displaySet.instance}
|
||||
metadata={displaySet.metadata}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
return (
|
||||
<div
|
||||
className={'DicomMicroscopyViewer'}
|
||||
style={style}
|
||||
onClick={() => {
|
||||
if (viewportId !== activeViewportId) {
|
||||
setViewportActive(viewportId);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div style={{ ...style, display: 'none' }}>
|
||||
<div style={{ ...style }} ref={overlayElement}>
|
||||
<div style={{ position: 'relative', height: '100%', width: '100%' }}>
|
||||
{displaySet && firstInstance.imageId && (
|
||||
<ViewportOverlay
|
||||
overlayData={overlayData}
|
||||
displaySet={displaySet}
|
||||
instance={displaySet.instance}
|
||||
metadata={displaySet.metadata}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{this.state.error ? (
|
||||
<h2>{JSON.stringify(this.state.error)}</h2>
|
||||
) : (
|
||||
<div
|
||||
style={style}
|
||||
ref={(ref: any) => {
|
||||
this.container.current = ref;
|
||||
this.props.resizeRef.current = ref;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{this.state.isLoaded ? null : (
|
||||
<LoadingIndicatorProgress className={'h-full w-full bg-black'} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<div
|
||||
style={style}
|
||||
ref={(ref: any) => {
|
||||
container.current = ref;
|
||||
resizeRef.current = ref;
|
||||
}}
|
||||
/>
|
||||
{isLoaded ? null : <LoadingIndicatorProgress className={'h-full w-full bg-black'} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DicomMicroscopyViewport;
|
||||
@@ -24,72 +24,66 @@ interface OverlayItem {
|
||||
* @param {*} extensionManager is used to load the image data.
|
||||
* @returns
|
||||
*/
|
||||
export const generateFromConfig = ({
|
||||
topLeft = [],
|
||||
topRight = [],
|
||||
bottomLeft = [],
|
||||
bottomRight = [],
|
||||
itemGenerator = () => {},
|
||||
}: {
|
||||
topLeft?: OverlayItem[];
|
||||
topRight?: OverlayItem[];
|
||||
bottomLeft?: OverlayItem[];
|
||||
bottomRight?: OverlayItem[];
|
||||
itemGenerator?: (props: any) => any;
|
||||
}) => {
|
||||
return (props: any) => {
|
||||
const topLeftClass = 'top-viewport left-viewport text-primary-light';
|
||||
const topRightClass = 'top-viewport right-viewport-scrollbar text-primary-light';
|
||||
const bottomRightClass = 'bottom-viewport right-viewport-scrollbar text-primary-light';
|
||||
const bottomLeftClass = 'bottom-viewport left-viewport text-primary-light';
|
||||
const overlay = 'absolute pointer-events-none microscopy-viewport-overlay';
|
||||
export const generateFromConfig = ({ config, overlayData, ...props }) => {
|
||||
const {
|
||||
topLeft = [],
|
||||
topRight = [],
|
||||
bottomLeft = [],
|
||||
bottomRight = [],
|
||||
}: {
|
||||
topLeft?: OverlayItem[];
|
||||
topRight?: OverlayItem[];
|
||||
bottomLeft?: OverlayItem[];
|
||||
bottomRight?: OverlayItem[];
|
||||
} = overlayData ?? {};
|
||||
const topLeftClass = 'top-viewport left-viewport text-primary-light';
|
||||
const topRightClass = 'top-viewport right-viewport-scrollbar text-primary-light';
|
||||
const bottomRightClass = 'bottom-viewport right-viewport-scrollbar text-primary-light';
|
||||
const bottomLeftClass = 'bottom-viewport left-viewport text-primary-light';
|
||||
const overlay = 'absolute pointer-events-none microscopy-viewport-overlay';
|
||||
|
||||
return (
|
||||
<>
|
||||
{topLeft && topLeft.length > 0 && (
|
||||
<div data-cy={'viewport-overlay-top-left'} className={classnames(overlay, topLeftClass)}>
|
||||
{listComponentGenerator({ ...props, list: topLeft, itemGenerator })}
|
||||
</div>
|
||||
)}
|
||||
{topRight && topRight.length > 0 && (
|
||||
<div
|
||||
data-cy={'viewport-overlay-top-right'}
|
||||
className={classnames(overlay, topRightClass)}
|
||||
>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: topRight,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{bottomRight && bottomRight.length > 0 && (
|
||||
<div
|
||||
data-cy={'viewport-overlay-bottom-right'}
|
||||
className={classnames(overlay, bottomRightClass)}
|
||||
>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: bottomRight,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{bottomLeft && bottomLeft.length > 0 && (
|
||||
<div
|
||||
data-cy={'viewport-overlay-bottom-left'}
|
||||
className={classnames(overlay, bottomLeftClass)}
|
||||
>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: bottomLeft,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{topLeft && topLeft.length > 0 && (
|
||||
<div data-cy={'viewport-overlay-top-left'} className={classnames(overlay, topLeftClass)}>
|
||||
{listComponentGenerator({ ...props, list: topLeft, itemGenerator })}
|
||||
</div>
|
||||
)}
|
||||
{topRight && topRight.length > 0 && (
|
||||
<div data-cy={'viewport-overlay-top-right'} className={classnames(overlay, topRightClass)}>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: topRight,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{bottomRight && bottomRight.length > 0 && (
|
||||
<div
|
||||
data-cy={'viewport-overlay-bottom-right'}
|
||||
className={classnames(overlay, bottomRightClass)}
|
||||
>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: bottomRight,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{bottomLeft && bottomLeft.length > 0 && (
|
||||
<div
|
||||
data-cy={'viewport-overlay-bottom-left'}
|
||||
className={classnames(overlay, bottomLeftClass)}
|
||||
>
|
||||
{listComponentGenerator({
|
||||
...props,
|
||||
list: bottomLeft,
|
||||
itemGenerator,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const itemGenerator = (props: any) => {
|
||||
@@ -123,4 +117,4 @@ const itemGenerator = (props: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default generateFromConfig({});
|
||||
export default generateFromConfig;
|
||||
@@ -0,0 +1,5 @@
|
||||
import { MeasurementItem } from '@ohif/ui';
|
||||
|
||||
export default {
|
||||
'microscopyPanel.measurementItem': MeasurementItem,
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import panelMeasurementItem from './customizations/panelMeasurementItem';
|
||||
|
||||
export default function getCustomizationModule() {
|
||||
return [
|
||||
{
|
||||
name: 'default',
|
||||
value: {
|
||||
...panelMeasurementItem,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { id } from './id';
|
||||
import React, { Suspense, useMemo } from 'react';
|
||||
import getPanelModule from './getPanelModule';
|
||||
import getCommandsModule from './getCommandsModule';
|
||||
import getCustomizationModule from './getCustomizationModule';
|
||||
import { Types } from '@ohif/core';
|
||||
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
@@ -82,9 +83,6 @@ const extension: Types.Extensions.Extension = {
|
||||
return (
|
||||
<MicroscopyViewport
|
||||
key={displaySetsKey}
|
||||
servicesManager={servicesManager}
|
||||
extensionManager={extensionManager}
|
||||
commandsManager={commandsManager}
|
||||
activeViewportId={activeViewportId}
|
||||
setViewportActive={(viewportId: string) => {
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
@@ -158,6 +156,8 @@ const extension: Types.Extensions.Extension = {
|
||||
getPanelModule,
|
||||
|
||||
getCommandsModule,
|
||||
|
||||
getCustomizationModule,
|
||||
};
|
||||
|
||||
export default extension;
|
||||
@@ -3,6 +3,286 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-pdf",
|
||||
"version": "3.10.0-beta.77",
|
||||
"version": "3.10.0-beta.112",
|
||||
"description": "OHIF extension for PDF display",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -30,8 +30,8 @@
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.10.0-beta.77",
|
||||
"@ohif/ui": "3.10.0-beta.77",
|
||||
"@ohif/core": "3.10.0-beta.112",
|
||||
"@ohif/ui": "3.10.0-beta.112",
|
||||
"dcmjs": "*",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
|
||||
Loaded 100 of 354 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user