Compare commits

...
147 Commits
Author SHA1 Message Date
ohif-bot 29eca3bd20 chore(version): Update package versions [skip ci] 2025-07-23 15:55:11 +00:00
ohif-bot 38bc497545 chore(version): version.json [skip ci] 2025-07-23 15:55:05 +00:00
Joe Boccanfuso d383be7c72 fix(security): Removed stylus package due to potential security vulnerability and we don't use it. (#5251) 2025-07-23 11:49:30 -04:00
Joe Boccanfuso d206cf9ba5 fix(security): Pin eslint-config-prettier and eslint-plugin-prettier versions. (#5246) 2025-07-22 12:02:57 -04:00
ohif-bot 1ad5acae9d chore(version): Update package versions [skip ci] 2025-06-09 15:06:36 +00:00
ohif-bot c19e32e0d1 chore(version): version.json [skip ci] 2025-06-09 15:06:30 +00:00
36813e0c2f chore: recovery 2 (#5014)
Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
Co-authored-by: Tang Cheng <45505657+tctco@users.noreply.github.com>
2025-06-09 10:58:06 -04:00
ohif-bot 9a4a40468f chore(version): Update package versions [skip ci] 2025-04-11 20:02:21 +00:00
ohif-bot 466a867e6a chore(version): version.json [skip ci] 2025-04-11 20:02:14 +00:00
aaba8bf1b0 fix: make datasource selection work and UI fixes (#4952)
Co-authored-by: Pedro Köhler <pedrokohlerbh@gmail.com>
Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
2025-04-11 15:57:29 -04:00
ohif-bot 0b6e9cba76 chore(version): Update package versions [skip ci] 2025-04-10 02:48:32 +00:00
ohif-bot 963664cb63 chore(version): version.json [skip ci] 2025-04-10 02:48:27 +00:00
sedghi 12fe1e107d chore: release 3p10 2025-04-09 22:41:26 -04:00
ohif-bot e1e9b5ccb1 chore(version): Update package versions [skip ci] 2025-04-09 20:54:34 +00:00
ohif-bot 6b7e73b78a chore(version): version.json [skip ci] 2025-04-09 20:54:27 +00:00
AlirezaandJoe Boccanfuso 43bc142439 fix(ui): Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels (#4938)
Co-authored-by: Joe Boccanfuso <joe.boccanfuso@radicalimaging.com>
2025-04-09 16:49:55 -04:00
ohif-bot c05ec1909f chore(version): Update package versions [skip ci] 2025-04-09 14:00:54 +00:00
ohif-bot c7529394ad chore(version): version.json [skip ci] 2025-04-09 14:00:48 +00:00
Pedro Köhler f6f60a63d2 fix: x-ray pixel spacing calibration (#4922) 2025-04-09 09:55:51 -04:00
ohif-bot 0d2ccc5830 chore(version): Update package versions [skip ci] 2025-04-09 03:01:36 +00:00
ohif-bot 08be5cc656 chore(version): version.json [skip ci] 2025-04-09 03:01:30 +00:00
Alireza c453c29449 docs: migration guides 3p10 (#4937) 2025-04-08 22:57:07 -04:00
ohif-bot a69dd8b1a0 chore(version): Update package versions [skip ci] 2025-04-08 22:38:59 +00:00
ohif-bot 17c5642a59 chore(version): version.json [skip ci] 2025-04-08 22:38:53 +00:00
Alireza bd2f843469 chore: update screenshopts for test (#4934) 2025-04-08 18:34:45 -04:00
ohif-bot 8b9b02d84c chore(version): Update package versions [skip ci] 2025-04-08 21:25:58 +00:00
ohif-bot c9958bafad chore(version): version.json [skip ci] 2025-04-08 21:25:52 +00:00
Dan Rukas 85f465968b ui(fix): small Create Report dialog fixes (#4935) 2025-04-08 17:21:08 -04:00
ohif-bot 47e491f1c8 chore(version): Update package versions [skip ci] 2025-04-08 16:10:38 +00:00
ohif-bot e56b53e897 chore(version): version.json [skip ci] 2025-04-08 16:10:32 +00:00
AlirezaandDan Rukas 2bdf4afa4d refactor(ui): Migrate components to ui-next (#4930)
Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
2025-04-08 12:06:07 -04:00
Dan Rukas 1b8729dded ui(components): CinePlayer updated for ui-next (#4932) 2025-04-08 12:03:35 -04:00
ohif-bot f71d370969 chore(version): Update package versions [skip ci] 2025-04-08 13:48:32 +00:00
ohif-bot 033831ee72 chore(version): version.json [skip ci] 2025-04-08 13:48:24 +00:00
Dan Rukas 49c08298fc ui(colors): Adds neutral color variable and updates scrollbars (#4933) 2025-04-08 09:43:30 -04:00
elawendeandErnst Lawende cfa202e89a fix(OIDC): Use new access_token after refresh (#4853)
Co-authored-by: Ernst Lawende <ernstl@bastion365.nl>
2025-04-08 09:43:06 -04:00
ohif-bot 391a5f3bdd chore(version): Update package versions [skip ci] 2025-04-07 20:50:11 +00:00
ohif-bot 64d65a6830 chore(version): version.json [skip ci] 2025-04-07 20:50:05 +00:00
Alireza 3653de7487 fix(segmentation): Add segment jump for new segments and make panels scrollable (#4928) 2025-04-07 16:45:29 -04:00
Dan Rukas a8ac297e16 ui(components): Viewport components updated to ui-next with design updates (#4886) 2025-04-07 16:45:05 -04:00
ohif-bot 4e09f85d5d chore(version): Update package versions [skip ci] 2025-04-07 14:09:45 +00:00
ohif-bot d2f187153d chore(version): version.json [skip ci] 2025-04-07 14:09:39 +00:00
Pedro Köhler 62e5a62066 feat: allow saving to same SR series (#4889) 2025-04-07 10:05:22 -04:00
ohif-bot 7b40963997 chore(version): Update package versions [skip ci] 2025-04-04 17:38:08 +00:00
ohif-bot 75493334cf chore(version): version.json [skip ci] 2025-04-04 17:38:00 +00:00
Pedro Köhler 746f2524eb fix(cine): Resolve Cine Player Faults on DisplaySet Update (#4909) 2025-04-04 13:33:36 -04:00
ohif-bot 0eb9ff235c chore(version): Update package versions [skip ci] 2025-04-04 16:16:04 +00:00
ohif-bot e9b95afd4c chore(version): version.json [skip ci] 2025-04-04 16:15:57 +00:00
Alireza fc33bd0d59 feat(image capture): Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes (#4924) 2025-04-04 12:11:29 -04:00
ohif-bot 479e280fdf chore(version): Update package versions [skip ci] 2025-04-04 16:07:02 +00:00
ohif-bot d4f81cd2b7 chore(version): version.json [skip ci] 2025-04-04 16:06:55 +00:00
nithin-trenserandDevu Jayalekshmi 54fded554e feat: Automate tracking prompts for a less disruptive annotation workflow (#4822)
Co-authored-by: Devu Jayalekshmi <devu.jayalekshmi@trenser.com>
2025-04-04 12:02:13 -04:00
ohif-bot c0391cea1b chore(version): Update package versions [skip ci] 2025-04-03 15:45:43 +00:00
ohif-bot a9e69eb36f chore(version): version.json [skip ci] 2025-04-03 15:45:36 +00:00
dependabot[bot] a52be6460b chore(deps): bump @babel/runtime-corejs2 from 7.25.7 to 7.26.10 (#4843)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:33:33 -04:00
dependabot[bot] 587b6423cb chore(deps): bump @babel/helpers from 7.26.0 to 7.26.10 in /platform/docs (#4861)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:33:19 -04:00
dependabot[bot] f52a32d6c5 chore(deps): bump @babel/runtime from 7.24.7 to 7.26.10 (#4860)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:33:09 -04:00
dependabot[bot] 8142c55b6a chore(deps): bump @babel/runtime-corejs3 from 7.26.0 to 7.26.10 in /platform/docs (#4859)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:32:54 -04:00
dependabot[bot] 14afb42e2c chore(deps): bump axios from 0.27.2 to 1.8.4 (#4905)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:32:45 -04:00
dependabot[bot] 4e8e4f1491 chore(deps): bump tar-fs from 2.1.1 to 2.1.2 (#4901)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:32:39 -04:00
dependabot[bot] 814a2c914b chore(deps): bump image-size from 1.2.0 to 1.2.1 in /platform/docs (#4912)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-03 11:32:31 -04:00
ohif-bot f4fb42adb2 chore(version): Update package versions [skip ci] 2025-04-02 22:23:12 +00:00
ohif-bot 0fee0236c2 chore(version): version.json [skip ci] 2025-04-02 22:23:05 +00:00
Alireza e7fe879318 chore: update dependabot (#4916) 2025-04-02 18:17:05 -04:00
ohif-bot a619634678 chore(version): Update package versions [skip ci] 2025-04-02 22:15:26 +00:00
ohif-bot 651a7dc574 chore(version): version.json [skip ci] 2025-04-02 22:15:20 +00:00
Alireza 8432d5f633 fix(seg): Enhance segmentation tools and UI, refactor code, and update dependencies (#4915) 2025-04-02 18:10:47 -04:00
ohif-bot 1dc00d3030 chore(version): Update package versions [skip ci] 2025-04-01 18:23:53 +00:00
ohif-bot 44d450c5b8 chore(version): version.json [skip ci] 2025-04-01 18:23:46 +00:00
Alireza c75a3f3af5 feat(segmentation): Enhance Segmentation with New AI and Once Click Tools (#4910) 2025-04-01 14:19:03 -04:00
ohif-bot 908482d2e0 chore(version): Update package versions [skip ci] 2025-04-01 13:35:34 +00:00
ohif-bot 6b26db387e chore(version): version.json [skip ci] 2025-04-01 13:35:27 +00:00
Dan Rukasandsedghi b7419fb6a1 ui(components): Adds InputNumber component and 4d panel updates (#4874)
Co-authored-by: sedghi <ar.sedghi@gmail.com>
2025-04-01 09:30:32 -04:00
ohif-bot c4045251fb chore(version): Update package versions [skip ci] 2025-03-31 13:14:52 +00:00
ohif-bot ec4cc64b06 chore(version): version.json [skip ci] 2025-03-31 13:14:46 +00:00
dxlin d9473e8db2 test: update Test/tmtv for v3.10.0-beta.136 (#4893) 2025-03-31 09:10:31 -04:00
ohif-bot 7f3fb9bb61 chore(version): Update package versions [skip ci] 2025-03-28 14:57:45 +00:00
ohif-bot 8cf5b52b84 chore(version): version.json [skip ci] 2025-03-28 14:57:39 +00:00
Alireza d7bd36544a fix: jump to measurement forever (#4867) 2025-03-28 10:53:04 -04:00
Alireza eafa2efda5 Revert "fix(measurement): fix for measurement jump is not switching series in 2DMPR (#4779)" (#4898) 2025-03-28 10:17:33 -04:00
arul-trenser 3f06c966eb fix(measurement): fix for measurement jump is not switching series in 2DMPR (#4779) 2025-03-28 10:14:19 -04:00
ohif-bot 951f95ef0a chore(version): Update package versions [skip ci] 2025-03-27 20:51:50 +00:00
ohif-bot 5737935a96 chore(version): version.json [skip ci] 2025-03-27 20:51:44 +00:00
Bill Wallace 459b0d223a fix: routerBasename setting (#4891) 2025-03-27 16:47:16 -04:00
ohif-bot c368d763b0 chore(version): Update package versions [skip ci] 2025-03-27 19:58:04 +00:00
ohif-bot 6b6f49b867 chore(version): version.json [skip ci] 2025-03-27 19:57:58 +00:00
Igor Octaviano 892d03fc3c fix(seg): multiframe SEG (#4890) 2025-03-27 15:52:22 -04:00
ohif-bot 2acc878f26 chore(version): Update package versions [skip ci] 2025-03-26 18:02:55 +00:00
ohif-bot 1df91fd104 chore(version): version.json [skip ci] 2025-03-26 18:02:48 +00:00
Pedro Köhler 9bde644fce fix: remove duplicated deleteMeasurements code (#4895) 2025-03-26 13:58:15 -04:00
ohif-bot 7f8fa1e1f4 chore(version): Update package versions [skip ci] 2025-03-26 17:44:41 +00:00
ohif-bot dce9c6b7c3 chore(version): version.json [skip ci] 2025-03-26 17:44:35 +00:00
Pedro Köhler 467acbd997 fix: datasource connection error style (#4888) 2025-03-26 13:40:09 -04:00
ohif-bot f90184d9d9 chore(version): Update package versions [skip ci] 2025-03-25 15:04:03 +00:00
ohif-bot cc9720dca2 chore(version): version.json [skip ci] 2025-03-25 15:03:57 +00:00
Alireza 4dd485bd2d fix(seg): orthanc seg (#4883) 2025-03-25 10:59:19 -04:00
ohif-bot 209d81f475 chore(version): Update package versions [skip ci] 2025-03-25 13:37:07 +00:00
ohif-bot 5c319ce4f0 chore(version): version.json [skip ci] 2025-03-25 13:37:00 +00:00
Bill Wallace f6fa509874 fix: Skip showing NaN for average pixel/max value (#4884) 2025-03-25 09:32:36 -04:00
Bill Wallace 8e47112d8e fix: Delete study measurements instead of all measurements (#4882) 2025-03-25 09:32:29 -04:00
Pedro Köhler 165c9dc710 fix: compare series date time (#4887) 2025-03-25 09:31:49 -04:00
ohif-bot 8faa9bf851 chore(version): Update package versions [skip ci] 2025-03-20 19:18:39 +00:00
ohif-bot 246c10da07 chore(version): version.json [skip ci] 2025-03-20 19:18:32 +00:00
Dan Rukas 782a6a0c88 ui(panels): Tool option components and responsive behavior for ROIThreshold (#4876) 2025-03-20 15:13:59 -04:00
ohif-bot 5293253ecd chore(version): Update package versions [skip ci] 2025-03-20 16:10:51 +00:00
ohif-bot 7f86ca1a2b chore(version): version.json [skip ci] 2025-03-20 16:10:45 +00:00
Pedro Köhler 01c3726ced feat: add customization to PanelStudyBrowser dbl click callback (#4871) 2025-03-20 12:06:26 -04:00
ohif-bot f73c485821 chore(version): Update package versions [skip ci] 2025-03-20 13:26:51 +00:00
ohif-bot 30a3965da7 chore(version): version.json [skip ci] 2025-03-20 13:26:45 +00:00
Bill Wallace df8efba82c feat: Group findings table values with custom components/grouping functions (#4712) 2025-03-20 09:22:45 -04:00
ohif-bot 0522d58d9b chore(version): Update package versions [skip ci] 2025-03-19 22:29:06 +00:00
ohif-bot 576ad47ebe chore(version): version.json [skip ci] 2025-03-19 22:29:00 +00:00
Alireza 5f112337b6 feat(segmentation): Enhance Segmentation Tools with Preview and Selection Features (#4870) 2025-03-19 18:24:33 -04:00
ohif-bot 20042f9109 chore(version): Update package versions [skip ci] 2025-03-19 15:57:55 +00:00
ohif-bot d59b9d88fa chore(version): version.json [skip ci] 2025-03-19 15:57:48 +00:00
Sai Shanmukha Narumanchi 7f229d5c23 fix(DicomWebDataSource) : Fix a missing null check in addRetrieveBulkDataNaturalized (#4866) 2025-03-19 11:52:56 -04:00
ohif-bot eac0308275 chore(version): Update package versions [skip ci] 2025-03-18 21:11:23 +00:00
ohif-bot c2f9252aef chore(version): version.json [skip ci] 2025-03-18 21:11:16 +00:00
Pedro Köhler 55d6393a3f feat: overlapping segments (#4849) 2025-03-18 17:07:13 -04:00
ohif-bot 5a6c2aeed9 chore(version): Update package versions [skip ci] 2025-03-18 14:57:07 +00:00
ohif-bot 751919c27b chore(version): version.json [skip ci] 2025-03-18 14:57:00 +00:00
Pedro Köhler fb93ef9219 fix: add back dicom tag browser SQ items (#4869) 2025-03-18 10:52:19 -04:00
ohif-bot a0a3a30361 chore(version): Update package versions [skip ci] 2025-03-18 03:01:26 +00:00
ohif-bot 64b196db20 chore(version): version.json [skip ci] 2025-03-18 03:01:20 +00:00
Dan Rukas c227c5742a ui(panels): PetSUV updates for ui-next and responsive layout (#4864) 2025-03-17 22:57:19 -04:00
ohif-bot 2c75638d1c chore(version): Update package versions [skip ci] 2025-03-18 02:39:10 +00:00
ohif-bot bf27da4174 chore(version): version.json [skip ci] 2025-03-18 02:39:04 +00:00
Alireza ec79b5523e feat(segmentation): segment statistics, labelmap interpolation and segment bidirectional (#4865) 2025-03-17 22:34:34 -04:00
ohif-bot 694f3e9611 chore(version): Update package versions [skip ci] 2025-03-17 15:51:26 +00:00
ohif-bot d33b1ade87 chore(version): version.json [skip ci] 2025-03-17 15:51:19 +00:00
Dan Rukasandsedghi abab3dc7ad ui(components): LayoutSelector recreated for ui-next (#4845)
Co-authored-by: sedghi <ar.sedghi@gmail.com>
2025-03-17 11:47:09 -04:00
Alireza b7fbf04230 fix(metadata): change the default values for cosines (#4863) 2025-03-17 11:44:05 -04:00
ohif-bot ec71721d49 chore(version): Update package versions [skip ci] 2025-03-17 15:09:28 +00:00
ohif-bot a265257569 chore(version): version.json [skip ci] 2025-03-17 15:09:22 +00:00
Dan Rukas 951c21fda8 ui(migrate) Migrate local view to new ui-next components (#4850) 2025-03-17 11:05:11 -04:00
Dan Rukas f916b2f40e ui(components): Adds InputFilter component to ui-next (#4848) 2025-03-17 11:04:42 -04:00
Pedro H. Köhler 841320adfb fix: max call stack exceeded for dicom tag browser (#4855) 2025-03-17 11:03:08 -04:00
ohif-bot 10976c2a48 chore(version): Update package versions [skip ci] 2025-03-17 15:01:31 +00:00
ohif-bot e2ab118217 chore(version): version.json [skip ci] 2025-03-17 15:01:24 +00:00
Alireza 8cd48c7f70 chore: run dependabot (#4862) 2025-03-17 10:56:39 -04:00
ohif-bot fd2f88920b chore(version): Update package versions [skip ci] 2025-03-17 14:25:30 +00:00
ohif-bot fdd33aea0f chore(version): version.json [skip ci] 2025-03-17 14:25:23 +00:00
Alireza ebe6fbaf31 feat: update vtk js (#4858) 2025-03-17 10:21:06 -04:00
ohif-bot bfa76de93b chore(version): Update package versions [skip ci] 2025-03-11 13:58:54 +00:00
ohif-bot 56c7c27ad9 chore(version): version.json [skip ci] 2025-03-11 13:58:47 +00:00
Ibrahim 3f70617c62 feat(viewport-gap): remove viewport gap and update border behavior (#4835) 2025-03-11 09:54:19 -04:00
Ibrahim 1f634bab45 feat(fonts): bundle fonts in OHIF and dont use google cdn (#4821)
[OHI-1681]
2025-03-11 09:50:46 -04:00
593 changed files with 29183 additions and 6666 deletions

No files matched your search

+2 -2
View File
@@ -242,7 +242,7 @@ jobs:
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build Docker image for arm64
name: Build Docker image for arm64 (Release)
command: |
# This file will exist if a new version was published by
# our command in the previous job.
@@ -369,7 +369,7 @@ jobs:
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Create and push multi-architecture manifest
name: Create and push multi-architecture manifest (Release)
command: |
# This file will exist if a new version was published by
# our command in the previous job.
+1 -1
View File
@@ -7,7 +7,7 @@ server {
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
try_files $uri $uri/ ${PUBLIC_URL}index.html;
add_header Cross-Origin-Resource-Policy same-origin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
+2 -3
View File
@@ -2,12 +2,11 @@
if [ -n "$SSL_PORT" ]
then
envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template > /etc/nginx/conf.d/default.conf
envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template | envsubst '${PUBLIC_URL}' > /etc/nginx/conf.d/default.conf
else
envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
envsubst '${PORT}:${PUBLIC_URL}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
fi
if [ -n "$APP_CONFIG" ]; then
echo "$APP_CONFIG" > /usr/share/nginx/html${PUBLIC_URL}app-config.js
echo "Using custom APP_CONFIG environment variable"
+19
View File
@@ -0,0 +1,19 @@
version: 2
enable-beta-ecosystems: true
updates:
- package-ecosystem: 'bun'
directory: '/'
schedule:
interval: 'daily'
labels: ['dependencies']
commit-message:
prefix: 'chore'
include: 'scope'
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'daily'
labels: ['dependencies']
commit-message:
prefix: 'chore'
include: 'scope'
+3 -4
View File
@@ -9,7 +9,7 @@ jobs:
timeout-minutes: 60
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.50.0-noble
image: mcr.microsoft.com/playwright:v1.51.1-noble
strategy:
fail-fast: false
matrix:
@@ -28,9 +28,8 @@ jobs:
- name: Set up Git safe directory
run: git config --global --add safe.directory /__w/Viewers/Viewers
- name: Run Playwright tests
run:
export NODE_OPTIONS="--max_old_space_size=8192" && bun x playwright test --shard=${{
matrix.shardIndex }}/${{ matrix.shardTotal }}
run: |
NODE_OPTIONS="--max_old_space_size=8192" TEST_ENV=true bun x playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
+5
View File
@@ -49,6 +49,7 @@ const defineValues = {
'process.env.LOCIZE_PROJECTID': JSON.stringify(process.env.LOCIZE_PROJECTID || ''),
'process.env.LOCIZE_API_KEY': JSON.stringify(process.env.LOCIZE_API_KEY || ''),
'process.env.REACT_APP_I18N_DEBUG': JSON.stringify(process.env.REACT_APP_I18N_DEBUG || ''),
'process.env.TEST_ENV': JSON.stringify(process.env.TEST_ENV || ''),
};
// Only redefine updated values. This avoids warning messages in the logs
@@ -168,6 +169,10 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
], //.concat(vtkRules),
},
resolve: {
+436
View File
@@ -3,6 +3,442 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
### Bug Fixes
* **security:** Pin eslint-config-prettier and eslint-plugin-prettier versions. ([#5246](https://github.com/OHIF/Viewers/issues/5246)) ([d206cf9](https://github.com/OHIF/Viewers/commit/d206cf9ba5e97fe047ca72fceedf8bb8bb869afe))
* **security:** Removed stylus package due to potential security vulnerability and we don't use it. ([#5251](https://github.com/OHIF/Viewers/issues/5251)) ([d383be7](https://github.com/OHIF/Viewers/commit/d383be7c720ec61f5bb1262ebe70893873718951))
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package ohif-monorepo-root
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
### Bug Fixes
* **OIDC:** Use new access_token after refresh ([#4853](https://github.com/OHIF/Viewers/issues/4853)) ([cfa202e](https://github.com/OHIF/Viewers/commit/cfa202e89a51f8b2e81b29954bb3a211c583fe28))
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
### Features
* allow saving to same SR series ([#4889](https://github.com/OHIF/Viewers/issues/4889)) ([62e5a62](https://github.com/OHIF/Viewers/commit/62e5a6206606ba7a16a56cf47456e52f892372da))
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
### Bug Fixes
* **cine:** Resolve Cine Player Faults on DisplaySet Update ([#4909](https://github.com/OHIF/Viewers/issues/4909)) ([746f252](https://github.com/OHIF/Viewers/commit/746f2524eb5e3ec1d36fbb35dc2cc5b55c7ba99f))
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
### Features
* Automate tracking prompts for a less disruptive annotation workflow ([#4822](https://github.com/OHIF/Viewers/issues/4822)) ([54fded5](https://github.com/OHIF/Viewers/commit/54fded554e934f2f75e00d456ebad7692d561225))
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
* **measurement:** fix for measurement jump is not switching series in 2DMPR ([#4779](https://github.com/OHIF/Viewers/issues/4779)) ([3f06c96](https://github.com/OHIF/Viewers/commit/3f06c966eb0bc9f6b5dcc477ccc7962f8a344c6f))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
### Bug Fixes
* routerBasename setting ([#4891](https://github.com/OHIF/Viewers/issues/4891)) ([459b0d2](https://github.com/OHIF/Viewers/commit/459b0d223a5867aaaabe1b5b61fd22b040ce5602))
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
### Bug Fixes
* remove duplicated deleteMeasurements code ([#4895](https://github.com/OHIF/Viewers/issues/4895)) ([9bde644](https://github.com/OHIF/Viewers/commit/9bde644fce6db56d7d0dd62a876312559b7b2beb))
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
### Bug Fixes
* datasource connection error style ([#4888](https://github.com/OHIF/Viewers/issues/4888)) ([467acbd](https://github.com/OHIF/Viewers/commit/467acbd997105d719bad3949a69ed0b5f8c553b4))
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
### Bug Fixes
* **seg:** orthanc seg ([#4883](https://github.com/OHIF/Viewers/issues/4883)) ([4dd485b](https://github.com/OHIF/Viewers/commit/4dd485bd2d927381bbc2910a2ec545c7d4c03868))
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* compare series date time ([#4887](https://github.com/OHIF/Viewers/issues/4887)) ([165c9dc](https://github.com/OHIF/Viewers/commit/165c9dc7104f63844a887b0ba91bd877c90c8471))
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
* Skip showing NaN for average pixel/max value ([#4884](https://github.com/OHIF/Viewers/issues/4884)) ([f6fa509](https://github.com/OHIF/Viewers/commit/f6fa5098744ff0058b007cf97e68d95c4b0e77c8))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
### Features
* add customization to PanelStudyBrowser dbl click callback ([#4871](https://github.com/OHIF/Viewers/issues/4871)) ([01c3726](https://github.com/OHIF/Viewers/commit/01c3726ced9afaa75b7c78fd22b380b42151c671))
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
### Features
* Group findings table values with custom components/grouping functions ([#4712](https://github.com/OHIF/Viewers/issues/4712)) ([df8efba](https://github.com/OHIF/Viewers/commit/df8efba82c268633ea05b5cb915061bceaec912c))
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
### Bug Fixes
* add back dicom tag browser SQ items ([#4869](https://github.com/OHIF/Viewers/issues/4869)) ([fb93ef9](https://github.com/OHIF/Viewers/commit/fb93ef921999010cbabe4bc7d8bef9b90c8efc71))
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
### Bug Fixes
* **metadata:** change the default values for cosines ([#4863](https://github.com/OHIF/Viewers/issues/4863)) ([b7fbf04](https://github.com/OHIF/Viewers/commit/b7fbf04230ec71e1812d12020e0b48d35a51b285))
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
### Bug Fixes
* max call stack exceeded for dicom tag browser ([#4855](https://github.com/OHIF/Viewers/issues/4855)) ([841320a](https://github.com/OHIF/Viewers/commit/841320adfb4cd009350e70c43a7661dc42800c7d))
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package ohif-monorepo-root
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
### Features
* **fonts:** bundle fonts in OHIF and dont use google cdn ([#4821](https://github.com/OHIF/Viewers/issues/4821)) ([1f634ba](https://github.com/OHIF/Viewers/commit/1f634bab456208a629747ef35a8ca7097d8ebf5f))
* **viewport-gap:** remove viewport gap and update border behavior ([#4835](https://github.com/OHIF/Viewers/issues/4835)) ([3f70617](https://github.com/OHIF/Viewers/commit/3f70617c629a0ef569dd2602e1f4a16fe1f77ba5))
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package ohif-monorepo-root
+7 -6
View File
@@ -62,9 +62,6 @@ RUN bun pm cache rm
RUN bun install
# Copy the local directory
COPY --link --exclude=yarn.lock --exclude=package.json --exclude=Dockerfile . .
# Do a second install to finalize things after the copy
RUN bun run show:config
RUN bun install
# Build here
# After install it should hopefully be stable until the local directory changes
@@ -72,6 +69,7 @@ ENV QUICK_BUILD true
# ENV GENERATE_SOURCEMAP=false
ARG APP_CONFIG=config/default.js
ARG PUBLIC_URL=/
ENV PUBLIC_URL=${PUBLIC_URL}
RUN bun run show:config
RUN bun run build
@@ -84,16 +82,19 @@ RUN ./.docker/compressDist.sh
# which runs Nginx using Alpine Linux
FROM nginxinc/nginx-unprivileged:1.27-alpine as final
#RUN apk add --no-cache bash
ARG PORT=80
ENV PORT=${PORT}
ARG PUBLIC_URL=/
ENV PUBLIC_URL=${PUBLIC_URL}
ARG PORT=80
ENV PORT=${PORT}
RUN rm /etc/nginx/conf.d/default.conf
USER nginx
COPY --chown=nginx:nginx .docker/Viewer-v3.x /usr/src
RUN chmod 777 /usr/src/entrypoint.sh
COPY --from=builder /usr/src/app/platform/app/dist /usr/share/nginx/html${PUBLIC_URL}
COPY --from=builder /usr/src/app/platform/app/dist/index.html /usr/share/nginx/html
# Copy paths that are renamed/redirected generally
# Microscopy libraries depend on root level include, so must be copied
COPY --from=builder /usr/src/app/platform/app/dist/dicom-microscopy-viewer /usr/share/nginx/html/dicom-microscopy-viewer
# In entrypoint.sh, app-config.js might be overwritten, so chmod it to be writeable.
# The nginx user cannot chmod it, so change to root.
USER root
-1
View File
@@ -1,5 +1,4 @@
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<div align="center">
<h1>OHIF Medical Imaging Viewer</h1>
<p><strong>The OHIF Viewer</strong> is a zero-footprint medical image viewer
+354
View File
@@ -3,6 +3,360 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
### Bug Fixes
* **security:** Pin eslint-config-prettier and eslint-plugin-prettier versions. ([#5246](https://github.com/OHIF/Viewers/issues/5246)) ([d206cf9](https://github.com/OHIF/Viewers/commit/d206cf9ba5e97fe047ca72fceedf8bb8bb869afe))
* **security:** Removed stylus package due to potential security vulnerability and we don't use it. ([#5251](https://github.com/OHIF/Viewers/issues/5251)) ([d383be7](https://github.com/OHIF/Viewers/commit/d383be7c720ec61f5bb1262ebe70893873718951))
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @externals/devDependencies
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @externals/devDependencies
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package @externals/devDependencies
+7 -10
View File
@@ -1,7 +1,7 @@
{
"name": "@externals/devDependencies",
"description": "External dev dependencies - put dev build dependencies here",
"version": "3.10.0-beta.120",
"version": "3.10.4",
"license": "MIT",
"private": true,
"engines": {
@@ -10,10 +10,10 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@kitware/vtk.js": "32.1.1",
"@kitware/vtk.js": "32.12.0",
"clsx": "^2.1.1",
"core-js": "^3.2.1",
"moment": "^2.9.4"
"moment": "^2.30.1"
},
"peerDependencies": {
"react": "^18.3.1",
@@ -39,14 +39,14 @@
"css-loader": "^6.8.1",
"dotenv": "^8.1.0",
"eslint": "^8.39.0",
"eslint-config-prettier": "^7.2.0",
"eslint-config-prettier": "7.2.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-flowtype": "^7.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-prettier": "5.5.1",
"eslint-plugin-promise": "^5.2.0",
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.4.0",
@@ -68,18 +68,15 @@
"postcss-import": "^14.0.2",
"postcss-loader": "^6.1.1",
"postcss-preset-env": "^7.4.3",
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.4",
"prettier": "3.6.2",
"prettier-plugin-tailwindcss": "0.6.9",
"react-refresh": "^0.14.2",
"semver": "^7.5.1",
"serve": "^14.2.4",
"shader-loader": "^1.3.1",
"shx": "^0.3.3",
"source-map-loader": "^4.0.1",
"start-server-and-test": "^1.10.0",
"style-loader": "^1.0.0",
"stylus": "^0.59.0",
"stylus-loader": "^7.1.3",
"terser-webpack-plugin": "^5.1.4",
"typescript": "5.5.4",
"unused-webpack-plugin": "2.4.0",
+344
View File
@@ -3,6 +3,350 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package @externals/dicom-microscopy-viewer
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@externals/dicom-microscopy-viewer",
"description": "External reference to dicom-microscopy-viewer",
"version": "3.10.0-beta.120",
"version": "3.10.4",
"license": "MIT",
"dependencies": {
"dicom-microscopy-viewer": "^0.46.1"
+566 -605
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1 +1 @@
834be4aaf186fd1690477df93bbc7111fd017cd0
d383be7c720ec61f5bb1262ebe70893873718951
@@ -3,6 +3,392 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**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.120",
"version": "3.10.4",
"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.120",
"@ohif/extension-cornerstone": "3.10.0-beta.120",
"@ohif/extension-default": "3.10.0-beta.120",
"@ohif/i18n": "3.10.0-beta.120",
"@ohif/core": "3.10.4",
"@ohif/extension-cornerstone": "3.10.4",
"@ohif/extension-default": "3.10.4",
"@ohif/i18n": "3.10.4",
"prop-types": "^15.6.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.0.4",
"@cornerstonejs/core": "^3.0.4",
"@kitware/vtk.js": "32.1.1",
"@cornerstonejs/adapters": "^3.11.6",
"@cornerstonejs/core": "^3.11.6",
"@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3"
}
}
@@ -3,6 +3,353 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
### Features
* Automate tracking prompts for a less disruptive annotation workflow ([#4822](https://github.com/OHIF/Viewers/issues/4822)) ([54fded5](https://github.com/OHIF/Viewers/commit/54fded554e934f2f75e00d456ebad7692d561225))
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.10.0-beta.120",
"version": "3.10.4",
"description": "DICOM RT read workflow",
"author": "OHIF",
"license": "MIT",
@@ -33,10 +33,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.10.0-beta.120",
"@ohif/extension-cornerstone": "3.10.0-beta.120",
"@ohif/extension-default": "3.10.0-beta.120",
"@ohif/i18n": "3.10.0-beta.120",
"@ohif/core": "3.10.4",
"@ohif/extension-cornerstone": "3.10.4",
"@ohif/extension-default": "3.10.4",
"@ohif/i18n": "3.10.4",
"prop-types": "^15.6.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -1,5 +1,3 @@
import { ButtonEnums } from '@ohif/ui';
const RESPONSE = {
NO_NEVER: -1,
CANCEL: 0,
@@ -13,13 +11,13 @@ function promptHydrateRT({
preHydrateCallbacks,
hydrateRTDisplaySet,
}: withAppTypes) {
const { uiViewportDialogService } = servicesManager.services;
const { uiViewportDialogService, customizationService } = servicesManager.services;
const extensionManager = servicesManager._extensionManager;
const appConfig = extensionManager._appConfig;
return new Promise(async function (resolve, reject) {
const promptResult = appConfig?.disableConfirmationPrompts
? RESPONSE.HYDRATE_SEG
: await _askHydrate(uiViewportDialogService, viewportId);
: await _askHydrate(uiViewportDialogService, customizationService, viewportId);
if (promptResult === RESPONSE.HYDRATE_SEG) {
preHydrateCallbacks?.forEach(callback => {
@@ -37,19 +35,23 @@ function promptHydrateRT({
});
}
function _askHydrate(uiViewportDialogService: AppTypes.UIViewportDialogService, viewportId) {
function _askHydrate(
uiViewportDialogService: AppTypes.UIViewportDialogService,
customizationService: AppTypes.CustomizationService,
viewportId
) {
return new Promise(function (resolve, reject) {
const message = 'Do you want to open this Segmentation?';
const message = customizationService.getCustomization('viewportNotification.hydrateRTMessage');
const actions = [
{
id: 'no-hydrate',
type: ButtonEnums.type.secondary,
type: 'secondary',
text: 'No',
value: RESPONSE.CANCEL,
},
{
id: 'yes-hydrate',
type: ButtonEnums.type.primary,
type: 'primary',
text: 'Yes',
value: RESPONSE.HYDRATE_SEG,
},
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { ViewportActionArrows } from '@ohif/ui';
import { ViewportActionArrows } from '@ohif/ui-next';
import { useViewportGrid } from '@ohif/ui-next';
import { utils } from '@ohif/extension-cornerstone';
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ViewportActionButton } from '@ohif/ui';
import { ViewportActionButton } from '@ohif/ui-next';
import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
@@ -15,7 +15,7 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
case false:
StatusIcon = () => (
<Icons.ByName
className="text-aqua-pale"
className="text-muted-foreground h-4 w-4"
name="status-untracked"
/>
);
@@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
{!ToolTipMessage && <StatusArea />}
</>
);
}
}
@@ -3,6 +3,395 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
### Features
* Automate tracking prompts for a less disruptive annotation workflow ([#4822](https://github.com/OHIF/Viewers/issues/4822)) ([54fded5](https://github.com/OHIF/Viewers/commit/54fded554e934f2f75e00d456ebad7692d561225))
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**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.120",
"version": "3.10.4",
"description": "DICOM SEG read workflow",
"author": "OHIF",
"license": "MIT",
@@ -33,10 +33,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.10.0-beta.120",
"@ohif/extension-cornerstone": "3.10.0-beta.120",
"@ohif/extension-default": "3.10.0-beta.120",
"@ohif/i18n": "3.10.0-beta.120",
"@ohif/core": "3.10.4",
"@ohif/extension-cornerstone": "3.10.4",
"@ohif/extension-default": "3.10.4",
"@ohif/i18n": "3.10.4",
"prop-types": "^15.6.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.0.4",
"@cornerstonejs/core": "^3.0.4",
"@kitware/vtk.js": "32.1.1",
"@cornerstonejs/adapters": "^3.11.6",
"@cornerstonejs/core": "^3.11.6",
"@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3"
}
}
@@ -1,22 +1,13 @@
import dcmjs from 'dcmjs';
import { Types } from '@ohif/core';
import { classes, Types } from '@ohif/core';
import { cache, metaData } from '@cornerstonejs/core';
import {
segmentation as cornerstoneToolsSegmentation,
Enums as cornerstoneToolsEnums,
utilities,
} from '@cornerstonejs/tools';
import { segmentation as cornerstoneToolsSegmentation } from '@cornerstonejs/tools';
import { adaptersRT, helpers, adaptersSEG } from '@cornerstonejs/adapters';
import { createReportDialogPrompt } from '@ohif/extension-default';
import { classes, DicomMetadataStore } from '@ohif/core';
import { DicomMetadataStore } from '@ohif/core';
import vtkImageMarchingSquares from '@kitware/vtk.js/Filters/General/ImageMarchingSquares';
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
import PROMPT_RESPONSES from '../../default/src/utils/_shared/PROMPT_RESPONSES';
const { segmentation: segmentationUtils } = utilities;
const { datasetToBlob } = dcmjs.data;
const getTargetViewport = ({ viewportId, viewportGridService }) => {
@@ -46,14 +37,8 @@ const commandsModule = ({
servicesManager,
extensionManager,
}: Types.Extensions.ExtensionParams): Types.Extensions.CommandsModule => {
const {
segmentationService,
uiDialogService,
displaySetService,
viewportGridService,
toolGroupService,
customizationService,
} = servicesManager.services as AppTypes.Services;
const { segmentationService, displaySetService, viewportGridService, toolGroupService } =
servicesManager.services as AppTypes.Services;
const actions = {
/**
@@ -287,21 +272,24 @@ const commandsModule = ({
* converts dataset to downloadable blob.
*
*/
downloadRTSS: ({ segmentationId }) => {
downloadRTSS: async ({ segmentationId }) => {
const segmentations = segmentationService.getSegmentation(segmentationId);
const vtkUtils = {
vtkImageMarchingSquares,
vtkDataArray,
vtkImageData,
};
const RTSS = generateRTSSFromSegmentations(
// inject colors to the segmentIndex
const firstRepresentation =
segmentationService.getRepresentationsForSegmentation(segmentationId)[0];
Object.entries(segmentations.segments).forEach(([segmentIndex, segment]) => {
segment.color = segmentationService.getSegmentColor(
firstRepresentation.viewportId,
segmentationId,
segmentIndex
);
});
const RTSS = await generateRTSSFromSegmentations(
segmentations,
classes.MetadataProvider,
DicomMetadataStore,
cache,
cornerstoneToolsEnums,
vtkUtils
DicomMetadataStore
);
try {
@@ -314,56 +302,9 @@ const commandsModule = ({
console.warn(e);
}
},
setBrushSize: ({ value, toolNames }) => {
const brushSize = Number(value);
toolGroupService.getToolGroupIds()?.forEach(toolGroupId => {
if (toolNames?.length === 0) {
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize);
} else {
toolNames?.forEach(toolName => {
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize, toolName);
});
}
});
},
setThresholdRange: ({
value,
toolNames = [
'ThresholdCircularBrush',
'ThresholdSphereBrush',
'ThresholdCircularBrushDynamic',
'ThresholdSphereBrushDynamic',
],
}) => {
const toolGroupIds = toolGroupService.getToolGroupIds();
if (!toolGroupIds?.length) {
return;
}
for (const toolGroupId of toolGroupIds) {
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
toolNames?.forEach(toolName => {
toolGroup.setToolConfiguration(toolName, {
threshold: {
range: value,
},
});
});
}
},
};
const definitions = {
/**
* Obsolete?
*/
loadSegmentationDisplaySetsForViewport: {
commandFn: actions.loadSegmentationDisplaySetsForViewport,
},
/**
* Obsolete?
*/
loadSegmentationsForViewport: {
commandFn: actions.loadSegmentationsForViewport,
},
@@ -380,12 +321,6 @@ const commandsModule = ({
downloadRTSS: {
commandFn: actions.downloadRTSS,
},
setBrushSize: {
commandFn: actions.setBrushSize,
},
setThresholdRange: {
commandFn: actions.setThresholdRange,
},
};
return {
@@ -177,12 +177,16 @@ async function _loadSegments({
throw new Error('referencedDisplaySet is missing for SEG');
}
const { instances: images } = referencedDisplaySet;
const imageIds = images.map(({ imageId }) => imageId);
let { imageIds } = referencedDisplaySet;
if (!imageIds) {
// try images
const { images } = referencedDisplaySet;
imageIds = images.map(image => image.imageId);
}
// Todo: what should be defaults here
const tolerance = 0.001;
const skipOverlapping = true;
eventTarget.addEventListener(Enums.Events.SEGMENTATION_LOAD_PROGRESS, evt => {
const { percentComplete } = evt.detail;
segmentationService._broadcastEvent(segmentationService.EVENTS.SEGMENT_LOADING_COMPLETE, {
@@ -190,11 +194,10 @@ async function _loadSegments({
});
});
const results = await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(
const results = await adaptersSEG.Cornerstone3D.Segmentation.createFromDICOMSegBuffer(
imageIds,
arrayBuffer,
metaData,
{ skipOverlapping, tolerance, eventTarget, triggerEvent }
{ metadataProvider: metaData, tolerance }
);
let usedRecommendedDisplayCIELabValue = true;
@@ -211,15 +214,6 @@ async function _loadSegments({
}
});
if (results.overlappingSegments) {
uiNotificationService.show({
title: 'Overlapping Segments',
message:
'Unsupported overlapping segments detected, segmentation rendering results may be incorrect.',
type: 'warning',
});
}
if (!usedRecommendedDisplayCIELabValue) {
// Display a notification about the non-utilization of RecommendedDisplayCIELabValue
uiNotificationService.show({
@@ -42,6 +42,13 @@ export function getToolbarModule({ servicesManager }: withAppTypes) {
};
}
if (!toolNames) {
return {
disabled: false,
// isActive: false,
};
}
const toolName = toolbarService.getToolNameForButton(button);
if (!toolGroup.hasTool(toolName) && !toolNames) {
@@ -1,5 +1,3 @@
import { ButtonEnums } from '@ohif/ui';
const RESPONSE = {
NO_NEVER: -1,
CANCEL: 0,
@@ -13,14 +11,14 @@ function promptHydrateSEG({
preHydrateCallbacks,
hydrateCallback,
}: withAppTypes) {
const { uiViewportDialogService } = servicesManager.services;
const { uiViewportDialogService, customizationService } = servicesManager.services;
const extensionManager = servicesManager._extensionManager;
const appConfig = extensionManager._appConfig;
return new Promise(async function (resolve, reject) {
const promptResult = appConfig?.disableConfirmationPrompts
? RESPONSE.HYDRATE_SEG
: await _askHydrate(uiViewportDialogService, viewportId);
: await _askHydrate(uiViewportDialogService, customizationService, viewportId);
if (promptResult === RESPONSE.HYDRATE_SEG) {
preHydrateCallbacks?.forEach(callback => {
@@ -39,19 +37,23 @@ function promptHydrateSEG({
});
}
function _askHydrate(uiViewportDialogService, viewportId) {
function _askHydrate(
uiViewportDialogService: AppTypes.UIViewportDialogService,
customizationService: AppTypes.CustomizationService,
viewportId
) {
return new Promise(function (resolve, reject) {
const message = 'Do you want to open this Segmentation?';
const message = customizationService.getCustomization('viewportNotification.hydrateSEGMessage');
const actions = [
{
id: 'no-hydrate',
type: ButtonEnums.type.secondary,
type: 'secondary',
text: 'No',
value: RESPONSE.CANCEL,
},
{
id: 'yes-hydrate',
type: ButtonEnums.type.primary,
type: 'primary',
text: 'Yes',
value: RESPONSE.HYDRATE_SEG,
},
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ViewportActionArrows } from '@ohif/ui';
import { ViewportActionArrows } from '@ohif/ui-next';
import { useViewportGrid } from '@ohif/ui-next';
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
import promptHydrateSEG from '../utils/promptHydrateSEG';
@@ -47,7 +47,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
const [viewportGrid, viewportGridService] = useViewportGrid();
// States
let selectedSegmentObjectIndex: number = 0;
const selectedSegmentObjectIndex: number = 0;
const { setPositionPresentation } = usePositionPresentationStore();
// Hydration means that the SEG is opened and segments are loaded into the
@@ -160,7 +160,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
displaySetInstanceUID: referencedDisplaySet.displaySetInstanceUID,
});
viewportGridService.setDisplaySetsForViewport({
commandsManager.runCommand('loadSegmentationDisplaySetsForViewport', {
viewportId,
displaySetInstanceUIDs: [referencedDisplaySet.displaySetInstanceUID],
});
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ViewportActionButton } from '@ohif/ui';
import { ViewportActionButton } from '@ohif/ui-next';
import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
@@ -15,7 +15,7 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
case false:
StatusIcon = () => (
<Icons.ByName
className="text-aqua-pale"
className="text-muted-foreground h-4 w-4"
name="status-untracked"
/>
);
@@ -56,4 +56,4 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
{!ToolTipMessage && <StatusArea />}
</>
);
}
}
@@ -3,6 +3,398 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
### Features
* allow saving to same SR series ([#4889](https://github.com/OHIF/Viewers/issues/4889)) ([62e5a62](https://github.com/OHIF/Viewers/commit/62e5a6206606ba7a16a56cf47456e52f892372da))
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
### Bug Fixes
* **cine:** Resolve Cine Player Faults on DisplaySet Update ([#4909](https://github.com/OHIF/Viewers/issues/4909)) ([746f252](https://github.com/OHIF/Viewers/commit/746f2524eb5e3ec1d36fbb35dc2cc5b55c7ba99f))
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.10.0-beta.120",
"version": "3.10.4",
"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.120",
"@ohif/extension-cornerstone": "3.10.0-beta.120",
"@ohif/extension-measurement-tracking": "3.10.0-beta.120",
"@ohif/ui": "3.10.0-beta.120",
"@ohif/core": "3.10.4",
"@ohif/extension-cornerstone": "3.10.4",
"@ohif/extension-measurement-tracking": "3.10.4",
"@ohif/ui": "3.10.4",
"dcmjs": "*",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.0.4",
"@cornerstonejs/core": "^3.0.4",
"@cornerstonejs/tools": "^3.0.4",
"@cornerstonejs/adapters": "^3.11.6",
"@cornerstonejs/core": "^3.11.6",
"@cornerstonejs/tools": "^3.11.6",
"classnames": "^2.3.2"
}
}
@@ -10,6 +10,15 @@ import hydrateStructuredReport from './utils/hydrateStructuredReport';
const { MeasurementReport } = adaptersSR.Cornerstone3D;
const { log } = OHIF;
interface Options {
SeriesDescription?: string;
SeriesInstanceUID?: string;
SeriesNumber?: number;
InstanceNumber?: number;
SeriesDate?: string;
SeriesTime?: string;
}
/**
* @param measurementData An array of measurements from the measurements service
* that you wish to serialize.
@@ -17,7 +26,7 @@ const { log } = OHIF;
* @param options Naturalized DICOM JSON headers to merge into the displaySet.
*
*/
const _generateReport = (measurementData, additionalFindingTypes, options = {}) => {
const _generateReport = (measurementData, additionalFindingTypes, options: Options = {}) => {
const filteredToolState = getFilteredCornerstoneToolState(
measurementData,
additionalFindingTypes
@@ -37,11 +46,14 @@ const _generateReport = (measurementData, additionalFindingTypes, options = {})
if (typeof dataset.SpecificCharacterSet === 'undefined') {
dataset.SpecificCharacterSet = 'ISO_IR 192';
}
dataset.InstanceNumber = options.InstanceNumber ?? 1;
return dataset;
};
const commandsModule = (props: withAppTypes) => {
const { servicesManager, extensionManager } = props;
const { servicesManager, extensionManager, commandsManager } = props;
const { customizationService, viewportGridService, displaySetService } = servicesManager.services;
const actions = {
@@ -156,12 +168,14 @@ const commandsModule = (props: withAppTypes) => {
const displaySets = displaySetService.getDisplaySetsForSeries(SeriesInstanceUIDs[0]);
if (displaySets.length) {
viewportGridService.setDisplaySetsForViewports([
{
viewportId: viewportGridService.getActiveViewportId(),
displaySetInstanceUIDs: [displaySets[0].displaySetInstanceUID],
},
]);
commandsManager.run('setDisplaySetsForViewports', {
viewportsToUpdate: [
{
viewportId: viewportGridService.getActiveViewportId(),
displaySetInstanceUIDs: [displaySets[0].displaySetInstanceUID],
},
],
});
}
},
};
@@ -5,7 +5,7 @@ import { ExtensionManager, useToolbar } from '@ohif/core';
import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSRModule';
import { ViewportActionArrows } from '@ohif/ui';
import { ViewportActionArrows } from '@ohif/ui-next';
import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet';
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';
import { useViewportGrid } from '@ohif/ui-next';
@@ -427,7 +427,7 @@ function _getStatusComponent({
case 3:
StatusIcon = () => (
<Icons.ByName
className="text-aqua-pale h-4 w-4"
className="text-muted-foreground h-4 w-4"
name="status-untracked"
/>
);
@@ -90,6 +90,7 @@ function _getDisplaySetsFromSeries(
SeriesDescription,
SeriesNumber,
SeriesDate,
SeriesTime,
ConceptNameCodeSequence,
SOPClassUID,
} = instance;
@@ -106,6 +107,7 @@ function _getDisplaySetsFromSeries(
SeriesDescription,
SeriesNumber,
SeriesDate,
SeriesTime,
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
@@ -77,28 +77,4 @@ export default function init({
SRRectangleROI: dashedLine,
global: {},
});
measurementService.subscribe(
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_LAYOUT,
({ viewportId, measurement, isConsumed }) => {
if (isConsumed) {
return;
}
try {
const currentViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const { viewPlaneNormal } = currentViewport.getCamera();
const referencedImageId = csToolsUtils.getClosestImageIdForStackViewport(
currentViewport as StackViewport,
measurement.points[0],
viewPlaneNormal
);
const imageIndex = (currentViewport as StackViewport)
.getImageIds()
.indexOf(referencedImageId);
csUtils.jumpToSlice(currentViewport.element, { imageIndex });
} catch (error) {
console.warn('Unable to jump to image based on measurement coordinate', error);
}
}
);
}
@@ -1,7 +1,7 @@
import React from 'react';
import { SOPClassHandlerId, SOPClassHandlerId3D } from './id';
import { ViewportActionButton } from '@ohif/ui';
import { ViewportActionButton } from '@ohif/ui-next';
import i18n from '@ohif/i18n';
export default function onModeEnter({ servicesManager }) {
@@ -3,6 +3,398 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
### Bug Fixes
* **cine:** Resolve Cine Player Faults on DisplaySet Update ([#4909](https://github.com/OHIF/Viewers/issues/4909)) ([746f252](https://github.com/OHIF/Viewers/commit/746f2524eb5e3ec1d36fbb35dc2cc5b55c7ba99f))
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
### Features
* Group findings table values with custom components/grouping functions ([#4712](https://github.com/OHIF/Viewers/issues/4712)) ([df8efba](https://github.com/OHIF/Viewers/commit/df8efba82c268633ea05b5cb915061bceaec912c))
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**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.120",
"version": "3.10.4",
"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.120",
"@ohif/extension-cornerstone": "3.10.0-beta.120",
"@ohif/extension-default": "3.10.0-beta.120",
"@ohif/i18n": "3.10.0-beta.120",
"@ohif/ui": "3.10.0-beta.120",
"@ohif/core": "3.10.4",
"@ohif/extension-cornerstone": "3.10.4",
"@ohif/extension-default": "3.10.4",
"@ohif/i18n": "3.10.4",
"@ohif/ui": "3.10.4",
"dcmjs": "*",
"dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8",
@@ -42,8 +42,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^3.0.4",
"@cornerstonejs/tools": "^3.0.4",
"@cornerstonejs/core": "^3.11.6",
"@cornerstonejs/tools": "^3.11.6",
"classnames": "^2.3.2"
}
}
@@ -262,7 +262,6 @@ function _getInstanceFromSegmentations(segmentations, { servicesManager }) {
}
function updateSegmentationsChartDisplaySet({ servicesManager }: withAppTypes): void {
debugger;
const { segmentationService } = servicesManager.services;
const segmentations = segmentationService.getSegmentations();
const { seriesMetadata, instance } =
@@ -263,7 +263,7 @@ const commandsModule = ({ commandsManager, servicesManager }: withAppTypes) => {
}
}
viewportGridService.setDisplaySetsForViewports(viewportsToUpdate);
commandsManager.run('setDisplaySetsForViewports', { viewportsToUpdate });
},
swapComputedWithDynamicDisplaySet: () => {
// Todo: this assumes there is only one dynamic display set in the viewer
@@ -313,7 +313,7 @@ const commandsModule = ({ commandsManager, servicesManager }: withAppTypes) => {
}
}
viewportGridService.setDisplaySetsForViewports(viewportsToUpdate);
commandsManager.run('setDisplaySetsForViewports', { viewportsToUpdate });
},
createNewLabelMapForDynamicVolume: async ({ label }) => {
const { viewports, activeViewportId } = viewportGridService.getState();
@@ -1,12 +1,24 @@
import React, { useState } from 'react';
import { Button, PanelSection, ButtonGroup, IconButton, InputNumber } from '@ohif/ui';
import { Icons, Tooltip, TooltipTrigger, TooltipContent, Numeric } from '@ohif/ui-next';
import {
Tabs,
TabsList,
TabsTrigger,
Button,
PanelSection,
Icons,
Tooltip,
TooltipTrigger,
TooltipContent,
Numeric,
} from '@ohif/ui-next';
import { Enums } from '@cornerstonejs/core';
const controlClassNames = {
sizeClassName: 'w-[58px] h-[28px]',
arrowsDirection: 'horizontal',
labelPosition: 'bottom',
// Helper function to safely convert any value to uppercase string
const toUpperCaseString = value => {
if (value === null || value === undefined) {
return '';
}
return String(value).toUpperCase();
};
const Header = ({ title, tooltip }) => (
@@ -16,18 +28,18 @@ const Header = ({ title, tooltip }) => (
<span>
<Icons.ByName
name="info-link"
className="text-primary-active h-[14px] w-[14px]"
className="text-primary h-3 w-3"
/>
</span>
</TooltipTrigger>
<TooltipContent
sideOffset={4}
className="bg-primary-dark max-w-xs p-2 text-white"
className="max-w-xs"
>
<div>{tooltip}</div>
</TooltipContent>
</Tooltip>
<span className="text-aqua-pale text-[11px] uppercase">{title}</span>
<span className="text-muted-foreground text-xs uppercase tracking-wide">{title}</span>
</div>
);
@@ -51,112 +63,138 @@ const DynamicVolumeControls = ({
const [computedView, setComputedView] = useState(false);
const [computeViewMode, setComputeViewMode] = useState(Enums.DynamicOperatorType.SUM);
// Wrapper for onGenerate to handle potential errors
const handleGenerate = () => {
try {
if (typeof onGenerate === 'function') {
onGenerate(computeViewMode);
} else {
console.error('onGenerate is not a function', onGenerate);
}
} catch (error) {
console.error('Error in onGenerate:', error);
}
};
return (
<div className="flex select-none flex-col">
<PanelSection
title="Controls"
childrenClassName="space-y-4 pb-5 px-5"
>
<div className="mt-2">
<Header
title="View"
tooltip={
'Select the view mode, 4D to view the dynamic volume or Computed to view the computed volume'
}
/>
<ButtonGroup className="mt-2 w-full">
<button
className="w-1/2"
onClick={() => {
setComputedView(false);
onDynamicClick?.();
<PanelSection defaultOpen={true}>
<PanelSection.Header>Controls</PanelSection.Header>
<PanelSection.Content className="bg-muted space-y-4 px-5 pt-2 pb-4">
<div className="mb-4">
<Header
title="View"
tooltip={
'Select the view mode, 4D to view the dynamic volume or Computed to view the computed volume'
}
/>
<Tabs
value={computedView ? 'computed' : '4d'}
onValueChange={value => {
const isComputed = value === 'computed';
setComputedView(isComputed);
if (!isComputed && typeof onDynamicClick === 'function') {
onDynamicClick();
}
}}
className="my-2 w-full"
>
4D
</button>
<button
className="w-1/2"
onClick={() => {
setComputedView(true);
}}
>
Computed
</button>
</ButtonGroup>
</div>
<div>
<DimensionGroupControls
onPlayPauseChange={onPlayPauseChange}
isPlaying={isPlaying}
computedView={computedView}
// fps
fps={fps}
onFpsChange={onFpsChange}
minFps={minFps}
maxFps={maxFps}
//
numDimensionGroups={numDimensionGroups}
onDimensionGroupChange={onDimensionGroupChange}
currentDimensionGroupNumber={currentDimensionGroupNumber}
/>
</div>
<div className={`mt-6 flex flex-col ${computedView ? '' : 'ohif-disabled'}`}>
<Header
title="Computed Operation"
tooltip={
<div>
Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to be
applied to the data set.
<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>
}
/>
<ButtonGroup
className="mt-2 w-full"
separated={true}
>
<button
className="w-1/2"
onClick={() => setComputeViewMode(Enums.DynamicOperatorType.SUM)}
>
{Enums.DynamicOperatorType.SUM.toString().toUpperCase()}
</button>
<button
className="w-1/2"
onClick={() => setComputeViewMode(Enums.DynamicOperatorType.AVERAGE)}
>
{Enums.DynamicOperatorType.AVERAGE.toString().toUpperCase()}
</button>
<button
className="w-1/2"
onClick={() => setComputeViewMode(Enums.DynamicOperatorType.SUBTRACT)}
>
{Enums.DynamicOperatorType.SUBTRACT.toString().toUpperCase()}
</button>
</ButtonGroup>
<div className="mt-2 w-full">
<Numeric.Container
mode="doubleRange"
min={1}
max={numDimensionGroups}
values={rangeValues}
onChange={onDoubleRangeChange}
>
<Numeric.DoubleRange showNumberInputs />
</Numeric.Container>
<TabsList className="w-full">
<TabsTrigger
value="4d"
className="w-1/2"
>
4D
</TabsTrigger>
<TabsTrigger
value="computed"
className="w-1/2"
>
Computed
</TabsTrigger>
</TabsList>
</Tabs>
</div>
<Button
className="mt-2 !h-[26px] !w-[115px] self-start !p-0"
onClick={() => {
onGenerate(computeViewMode);
}}
>
Generate
</Button>
</div>
<div>
<DimensionGroupControls
onPlayPauseChange={onPlayPauseChange}
isPlaying={isPlaying}
computedView={computedView}
// fps
fps={fps}
onFpsChange={onFpsChange}
minFps={minFps}
maxFps={maxFps}
//
numDimensionGroups={numDimensionGroups}
onDimensionGroupChange={onDimensionGroupChange}
currentDimensionGroupNumber={currentDimensionGroupNumber}
/>
</div>
<div className={`mt-3 flex flex-col ${computedView ? '' : 'ohif-disabled'}`}>
<Header
title="Computed Operation"
tooltip={
<div>
Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to
be applied to the data set.
<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>
}
/>
<Tabs
value={String(computeViewMode)}
onValueChange={value => {
setComputeViewMode(value);
}}
className="mt-2 w-full"
>
<TabsList className="w-full gap-1">
{' '}
<TabsTrigger
value={String(Enums.DynamicOperatorType.SUM)}
className="w-1/3"
>
{toUpperCaseString(Enums.DynamicOperatorType.SUM)}
</TabsTrigger>
<TabsTrigger
value={String(Enums.DynamicOperatorType.AVERAGE)}
className="w-1/3"
>
{toUpperCaseString(Enums.DynamicOperatorType.AVERAGE)}
</TabsTrigger>
<TabsTrigger
value={String(Enums.DynamicOperatorType.SUBTRACT)}
className="w-1/3"
>
{toUpperCaseString(Enums.DynamicOperatorType.SUBTRACT)}
</TabsTrigger>
</TabsList>
</Tabs>
<div className="mt-2 w-full">
<Numeric.Container
mode="doubleRange"
min={1}
max={numDimensionGroups || 1}
values={rangeValues || [1, numDimensionGroups || 1]}
onChange={onDoubleRangeChange || (() => {})}
>
<Numeric.DoubleRange showNumberInputs />
</Numeric.Container>
</div>
<Button
variant="default"
size="sm"
className="mt-2 h-[26px] w-[115px] self-start p-0"
onClick={handleGenerate}
>
Generate
</Button>
</div>
</PanelSection.Content>
</PanelSection>
</div>
);
@@ -179,7 +217,7 @@ function DimensionGroupControls({
const getPlayPauseIconName = () => (isPlaying ? 'icon-pause' : 'icon-play');
return (
<div className={computedView && 'ohif-disabled'}>
<div className={computedView ? 'ohif-disabled' : ''}>
<Header
title="4D Controls"
tooltip={
@@ -192,32 +230,56 @@ function DimensionGroupControls({
}
/>
<div className="mt-3 flex justify-between">
<IconButton
<Button
id="play-pause-button"
className="bg-customblue-30 h-[26px] w-[58px] rounded-[4px]"
onClick={() => onPlayPauseChange(!isPlaying)}
variant="secondary"
size="default"
className="w-[58px]"
onClick={() => {
if (typeof onPlayPauseChange === 'function') {
onPlayPauseChange(!isPlaying);
}
}}
>
<Icons.ByName
name={getPlayPauseIconName()}
className="active:text-primary-light hover:bg-customblue-300 h-[24px] w-[24px] cursor-pointer text-white"
className="text-foreground h-[24px] w-[24px]"
/>
</IconButton>
<InputNumber
value={currentDimensionGroupNumber}
onChange={onDimensionGroupChange}
minValue={1}
maxValue={numDimensionGroups}
label="Group"
{...controlClassNames}
/>
<InputNumber
value={fps}
onChange={onFpsChange}
minValue={minFps}
maxValue={maxFps}
{...controlClassNames}
label="FPS"
/>
</Button>
<Numeric.Container
mode="stepper"
value={currentDimensionGroupNumber || 1}
onChange={onDimensionGroupChange || (() => {})}
min={1}
max={numDimensionGroups || 1}
step={1}
>
<div className="flex flex-col items-center">
<Numeric.NumberStepper
className="h-[28px] w-[58px]"
direction="horizontal"
/>
<Numeric.Label className="text-muted-foreground mt-1 text-sm">Frame</Numeric.Label>
</div>
</Numeric.Container>
<Numeric.Container
mode="stepper"
value={fps || 1}
onChange={onFpsChange || (() => {})}
min={minFps || 1}
max={maxFps || 30}
step={1}
>
<div className="flex flex-col items-center">
<Numeric.NumberStepper
className="h-[28px] w-[58px]"
direction="horizontal"
/>
<Numeric.Label className="text-muted-foreground mt-1 text-sm">FPS</Numeric.Label>
</div>
</Numeric.Container>
</div>
</div>
);
@@ -1,71 +0,0 @@
import React from 'react';
import { InputDoubleRange } from '@ohif/ui';
import { Select } from '@ohif/ui';
import { Button } from '@ohif/ui';
import PropTypes from 'prop-types';
const GenerateVolume = ({
rangeValues,
handleSliderChange,
operationsUI,
options,
handleGenerateOptionsChange,
onGenerateImage,
returnTo4D,
displayingComputedVolume,
}) => {
return (
<>
<div>
<div className="mb-2 text-white">Computed Image</div>
<Select
closeMenuOnSelect={true}
className="border-primary-main mr-2 bg-black text-white "
options={operationsUI}
placeholder={operationsUI.find(option => option.value === options.Operation).placeHolder}
value={options.Operation}
onChange={({ value }) => {
handleGenerateOptionsChange({
Operation: value,
});
}}
/>
<InputDoubleRange
values={rangeValues}
onChange={handleSliderChange}
minValue={rangeValues[0] || 1}
maxValue={rangeValues[1] || 2}
showLabel={true}
step={1}
/>
<div className="flex space-x-2">
<Button
onClick={onGenerateImage}
className="w-1/2"
>
Generate
</Button>
<Button
onClick={returnTo4D}
disabled={!displayingComputedVolume}
className="w-1/2"
>
Return To 4D
</Button>
</div>
</div>
</>
);
};
GenerateVolume.propTypes = {
rangeValues: PropTypes.array.isRequired,
handleSliderChange: PropTypes.func.isRequired,
operationsUI: PropTypes.array.isRequired,
options: PropTypes.object.isRequired,
handleGenerateOptionsChange: PropTypes.func.isRequired,
onGenerateImage: PropTypes.func.isRequired,
returnTo4D: PropTypes.func.isRequired,
};
export default GenerateVolume;
@@ -1,5 +1,5 @@
import React, { useEffect, useState, useRef } from 'react';
import { useCine } from '@ohif/ui';
import { useCine } from '@ohif/ui-next';
import { useViewportGrid } from '@ohif/ui-next';
import { utilities as csUtils, volumeLoader, eventTarget, Enums, cache } from '@cornerstonejs/core';
import { utilities as cstUtils } from '@cornerstonejs/tools';
+400
View File
@@ -3,6 +3,406 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.10.4](https://github.com/OHIF/Viewers/compare/v3.10.2...v3.10.4) (2025-07-23)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [3.10.2](https://github.com/OHIF/Viewers/compare/v3.10.1...v3.10.2) (2025-06-09)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [3.10.1](https://github.com/OHIF/Viewers/compare/v3.10.0...v3.10.1) (2025-04-11)
### Bug Fixes
* make datasource selection work and UI fixes ([#4952](https://github.com/OHIF/Viewers/issues/4952)) ([aaba8bf](https://github.com/OHIF/Viewers/commit/aaba8bf1b04be6c00a88f1f5f29cb24133b0c39e))
# [3.10.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.10.0) (2025-04-10)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
### Bug Fixes
* **ui:** Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels ([#4938](https://github.com/OHIF/Viewers/issues/4938)) ([43bc142](https://github.com/OHIF/Viewers/commit/43bc142439aab1a6514ba1711f86d64ac8bb1acb))
# [3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
### Bug Fixes
* x-ray pixel spacing calibration ([#4922](https://github.com/OHIF/Viewers/issues/4922)) ([f6f60a6](https://github.com/OHIF/Viewers/commit/f6f60a63d2780cece8ade012a71b93cb3c7c4035))
# [3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
### Bug Fixes
* **segmentation:** Add segment jump for new segments and make panels scrollable ([#4928](https://github.com/OHIF/Viewers/issues/4928)) ([3653de7](https://github.com/OHIF/Viewers/commit/3653de748731199d130f02200becde78c07d3303))
# [3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
### Bug Fixes
* **cine:** Resolve Cine Player Faults on DisplaySet Update ([#4909](https://github.com/OHIF/Viewers/issues/4909)) ([746f252](https://github.com/OHIF/Viewers/commit/746f2524eb5e3ec1d36fbb35dc2cc5b55c7ba99f))
# [3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
### Features
* **image capture:** Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes ([#4924](https://github.com/OHIF/Viewers/issues/4924)) ([fc33bd0](https://github.com/OHIF/Viewers/commit/fc33bd0d594a1ac8de79b11080ead48630a8ca27))
# [3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
### Features
* Automate tracking prompts for a less disruptive annotation workflow ([#4822](https://github.com/OHIF/Viewers/issues/4822)) ([54fded5](https://github.com/OHIF/Viewers/commit/54fded554e934f2f75e00d456ebad7692d561225))
# [3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
### Bug Fixes
* **seg:** Enhance segmentation tools and UI, refactor code, and update dependencies ([#4915](https://github.com/OHIF/Viewers/issues/4915)) ([8432d5f](https://github.com/OHIF/Viewers/commit/8432d5f6330b300ac6760b32372be382210ed05b))
# [3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
### Features
* **segmentation:** Enhance Segmentation with New AI and Once Click Tools ([#4910](https://github.com/OHIF/Viewers/issues/4910)) ([c75a3f3](https://github.com/OHIF/Viewers/commit/c75a3f3af58c4cd29c349338e4065269d8d9f387))
# [3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
### Bug Fixes
* jump to measurement forever ([#4867](https://github.com/OHIF/Viewers/issues/4867)) ([d7bd365](https://github.com/OHIF/Viewers/commit/d7bd36544a039deae30e179404452cde738b8b03))
* **measurement:** fix for measurement jump is not switching series in 2DMPR ([#4779](https://github.com/OHIF/Viewers/issues/4779)) ([3f06c96](https://github.com/OHIF/Viewers/commit/3f06c966eb0bc9f6b5dcc477ccc7962f8a344c6f))
# [3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
### Bug Fixes
* **seg:** multiframe SEG ([#4890](https://github.com/OHIF/Viewers/issues/4890)) ([892d03f](https://github.com/OHIF/Viewers/commit/892d03fc3ca85a2772bf49ff5efc8014b9b2cdc9))
# [3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
### Bug Fixes
* remove duplicated deleteMeasurements code ([#4895](https://github.com/OHIF/Viewers/issues/4895)) ([9bde644](https://github.com/OHIF/Viewers/commit/9bde644fce6db56d7d0dd62a876312559b7b2beb))
# [3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
### Bug Fixes
* Delete study measurements instead of all measurements ([#4882](https://github.com/OHIF/Viewers/issues/4882)) ([8e47112](https://github.com/OHIF/Viewers/commit/8e47112d8e9fe86d57a587e3445b12d5f98d0161))
* Skip showing NaN for average pixel/max value ([#4884](https://github.com/OHIF/Viewers/issues/4884)) ([f6fa509](https://github.com/OHIF/Viewers/commit/f6fa5098744ff0058b007cf97e68d95c4b0e77c8))
# [3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
### Features
* Group findings table values with custom components/grouping functions ([#4712](https://github.com/OHIF/Viewers/issues/4712)) ([df8efba](https://github.com/OHIF/Viewers/commit/df8efba82c268633ea05b5cb915061bceaec912c))
# [3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
### Features
* **segmentation:** Enhance Segmentation Tools with Preview and Selection Features ([#4870](https://github.com/OHIF/Viewers/issues/4870)) ([5f11233](https://github.com/OHIF/Viewers/commit/5f112337b6ce26036bc5a156e26a0023c9de59ca))
# [3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
### Features
* overlapping segments ([#4849](https://github.com/OHIF/Viewers/issues/4849)) ([55d6393](https://github.com/OHIF/Viewers/commit/55d6393a3f3ed5b961809f77bf13a84da3c10be8))
# [3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
### Features
* **segmentation:** segment statistics, labelmap interpolation and segment bidirectional ([#4865](https://github.com/OHIF/Viewers/issues/4865)) ([ec79b55](https://github.com/OHIF/Viewers/commit/ec79b5523e262efd775149cd86b87b870d05d6bc))
# [3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
### Features
* update vtk js ([#4858](https://github.com/OHIF/Viewers/issues/4858)) ([ebe6fba](https://github.com/OHIF/Viewers/commit/ebe6fbaf31a497b4941178cbb734176d2fb989c2))
# [3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone
# [3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
**Note:** Version bump only for package @ohif/extension-cornerstone
+11 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "3.10.0-beta.120",
"version": "3.10.4",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -38,9 +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": "^3.0.4",
"@ohif/core": "3.10.0-beta.120",
"@ohif/ui": "3.10.0-beta.120",
"@cornerstonejs/dicom-image-loader": "^3.11.6",
"@ohif/core": "3.10.4",
"@ohif/ui": "3.10.4",
"dcmjs": "*",
"dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8",
@@ -51,12 +51,14 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.0.4",
"@cornerstonejs/core": "^3.0.4",
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
"@cornerstonejs/tools": "^3.0.4",
"@cornerstonejs/adapters": "^3.11.6",
"@cornerstonejs/ai": "^3.11.6",
"@cornerstonejs/core": "^3.11.6",
"@cornerstonejs/labelmap-interpolation": "^3.11.6",
"@cornerstonejs/polymorphic-segmentation": "^3.11.6",
"@cornerstonejs/tools": "^3.11.6",
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.1.1",
"@kitware/vtk.js": "32.12.0",
"html2canvas": "^1.4.1",
"lodash.compact": "^3.0.1",
"lodash.debounce": "^4.0.8",
@@ -3,7 +3,8 @@ 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, useViewportDialog } from '@ohif/ui';
import { AllInOneMenu } from '@ohif/ui-next';
import { useViewportDialog } from '@ohif/ui-next';
import type { Types as csTypes } from '@cornerstonejs/core';
import { setEnabledElement } from '../state';
@@ -23,12 +24,6 @@ import { WITH_NAVIGATION } from '../services/ViewportService/CornerstoneViewport
const STACK = 'stack';
/**
* Caches the jump to measurement operation, so that if display set is shown,
* it can jump to the measurement.
*/
let cacheJumpToMeasurementEvent;
// Todo: This should be done with expose of internal API similar to react-vtkjs-viewport
// Then we don't need to worry about the re-renders if the props change.
const OHIFCornerstoneViewport = React.memo(
@@ -99,12 +94,13 @@ const OHIFCornerstoneViewport = React.memo(
cornerstoneCacheService,
viewportActionCornersService,
customizationService,
measurementService,
} = servicesManager.services;
const [viewportDialogState] = useViewportDialog();
// useCallback for scroll bar height calculation
const setImageScrollBarHeight = useCallback(() => {
const scrollbarHeight = `${elementRef.current.clientHeight - 40}px`;
const scrollbarHeight = `${elementRef.current.clientHeight - 10}px`;
setScrollbarHeight(scrollbarHeight);
}, [elementRef]);
@@ -263,14 +259,6 @@ const OHIFCornerstoneViewport = React.memo(
const presentations = getViewportPresentations(viewportId, viewportOptions);
let measurement;
if (cacheJumpToMeasurementEvent?.viewportId === viewportId) {
measurement = cacheJumpToMeasurementEvent.measurement;
// Delete the position presentation so that viewport navigates direct
presentations.positionPresentation = null;
cacheJumpToMeasurementEvent = null;
}
// Note: This is a hack to get the grid to re-render the OHIFCornerstoneViewport component
// Used for segmentation hydration right now, since the logic to decide whether
// a viewport needs to render a segmentation lives inside the CornerstoneViewportService
@@ -288,10 +276,6 @@ const OHIFCornerstoneViewport = React.memo(
displaySetOptions,
presentations
);
if (measurement) {
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
}
};
loadViewportData();
@@ -312,16 +296,13 @@ const OHIFCornerstoneViewport = React.memo(
return;
}
const unsubscribeFromJumpToMeasurementEvents = _subscribeToJumpToMeasurementEvents(
elementRef,
viewportId,
servicesManager
const { unsubscribe } = measurementService.subscribe(
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
event => handleJumpToMeasurement(event, elementRef, viewportId, cornerstoneViewportService)
);
_checkForCachedJumpToMeasurementEvents(elementRef, viewportId, displaySets, servicesManager);
return () => {
unsubscribeFromJumpToMeasurementEvents();
unsubscribe();
};
}, [displaySets, elementRef, viewportId, isJumpToMeasurementDisabled, servicesManager]);
@@ -427,99 +408,52 @@ const OHIFCornerstoneViewport = React.memo(
areEqual
);
function _subscribeToJumpToMeasurementEvents(elementRef, viewportId, servicesManager) {
const { measurementService, cornerstoneViewportService } = servicesManager.services;
// Helper function to handle jumping to measurements
function handleJumpToMeasurement(event, elementRef, viewportId, cornerstoneViewportService) {
const { measurement, isConsumed } = event;
if (!measurement || isConsumed) {
return;
}
const { unsubscribe } = measurementService.subscribe(
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
props => {
cacheJumpToMeasurementEvent = props;
const { viewportId: jumpId, measurement, isConsumed } = props;
if (!measurement || isConsumed) {
return;
}
if (cacheJumpToMeasurementEvent.cornerstoneViewport === undefined) {
// Decide on which viewport should handle this
cacheJumpToMeasurementEvent.cornerstoneViewport =
cornerstoneViewportService.getViewportIdToJump(jumpId, {
displaySetInstanceUID: measurement.displaySetInstanceUID,
...measurement.metadata,
referencedImageId:
measurement.referencedImageId || measurement.metadata?.referencedImageId,
});
}
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
return;
}
_jumpToMeasurement(measurement, elementRef, viewportId, servicesManager);
}
const enabledElement = getEnabledElement(elementRef.current);
if (!enabledElement) {
return;
}
const viewport = enabledElement.viewport as csTypes.IStackViewport | csTypes.IVolumeViewport;
const { metadata, displaySetInstanceUID } = measurement;
const viewportDisplaySets = cornerstoneViewportService.getViewportDisplaySets(viewportId);
const showingDisplaySet = viewportDisplaySets.find(
ds => ds.displaySetInstanceUID === displaySetInstanceUID
);
return unsubscribe;
}
let metadataToUse = metadata;
// if it is not showing the displaySet we need to remove the FOR from the metadata
if (!showingDisplaySet) {
metadataToUse = {
...metadata,
FrameOfReferenceUID: undefined,
};
}
// Check if there is a queued jumpToMeasurement event
function _checkForCachedJumpToMeasurementEvents(
elementRef,
viewportId,
displaySets,
servicesManager
) {
if (!cacheJumpToMeasurementEvent) {
return;
}
if (cacheJumpToMeasurementEvent.isConsumed) {
cacheJumpToMeasurementEvent = null;
return;
}
const displaysUIDs = displaySets.map(displaySet => displaySet.displaySetInstanceUID);
if (!displaysUIDs?.length) {
// Todo: make it work with cases where we want to define FOR based measurements too
if (!viewport.isReferenceViewable(metadataToUse, WITH_NAVIGATION)) {
return;
}
// Jump to measurement if the measurement exists
const { measurement } = cacheJumpToMeasurementEvent;
if (measurement && elementRef) {
if (displaysUIDs.includes(measurement?.displaySetInstanceUID)) {
_jumpToMeasurement(measurement, elementRef, viewportId, servicesManager);
}
try {
viewport.setViewReference(metadata);
viewport.render();
} catch (e) {
console.warn('Unable to apply', metadata, e);
}
}
function _jumpToMeasurement(measurement, targetElementRef, viewportId, servicesManager) {
const { viewportGridService } = servicesManager.services;
const targetElement = targetElementRef.current;
// Todo: setCornerstoneMeasurementActive should be handled by the toolGroupManager
// to set it properly
// setCornerstoneMeasurementActive(measurement);
viewportGridService.setActiveViewportId(viewportId);
const enabledElement = getEnabledElement(targetElement);
if (enabledElement) {
// See how the jumpToSlice() of Cornerstone3D deals with imageIdx param.
const viewport = enabledElement.viewport as csTypes.IStackViewport | csTypes.IVolumeViewport;
const { metadata } = measurement;
if (!viewport.isReferenceViewable(metadata, WITH_NAVIGATION)) {
console.log("Reference isn't viewable, postponing until updated");
return;
}
try {
viewport.setViewReference(metadata);
} catch (e) {
console.warn('Unable to apply', metadata, e);
}
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
// Jump to measurement consumed, remove.
cacheJumpToMeasurementEvent?.consume?.();
cacheJumpToMeasurementEvent = null;
}
cs3DTools.annotation.selection.setAnnotationSelected(measurement.uid);
event?.consume?.();
}
function _rehydrateSynchronizers(viewportId: string, syncGroupService: any) {
@@ -3,7 +3,7 @@ import { vec3 } from 'gl-matrix';
import PropTypes from 'prop-types';
import { metaData, Enums, utilities } from '@cornerstonejs/core';
import type { ImageSliceData } from '@cornerstonejs/core/types';
import { ViewportOverlay } from '@ohif/ui';
import { ViewportOverlay } from '@ohif/ui-next';
import type { InstanceMetadata } from '@ohif/core/src/types';
import { formatDICOMDate, formatDICOMTime, formatNumberPrecision } from './utils';
import { utils } from '@ohif/core';
@@ -368,7 +368,7 @@ function OverlayItem(props) {
title={title}
>
{label ? <span className="mr-1 shrink-0">{label}</span> : null}
<span className="ml-1 mr-2 shrink-0">{value}</span>
<span className="ml-0 mr-2 shrink-0">{value}</span>
</div>
);
}
@@ -387,10 +387,10 @@ function VOIOverlayItem({ voi, customization }: OverlayItemProps) {
className="overlay-item flex flex-row"
style={{ color: customization?.color }}
>
<span className="mr-1 shrink-0">W:</span>
<span className="ml-1 mr-2 shrink-0">{windowWidth.toFixed(0)}</span>
<span className="mr-1 shrink-0">L:</span>
<span className="ml-1 shrink-0">{windowCenter.toFixed(0)}</span>
<span className="mr-0.5 shrink-0 opacity-[0.67]">W:</span>
<span className="mr-2.5 shrink-0">{windowWidth.toFixed(0)}</span>
<span className="mr-0.5 shrink-0 opacity-[0.67]">L:</span>
<span className="shrink-0">{windowCenter.toFixed(0)}</span>
</div>
);
}
@@ -404,7 +404,7 @@ function ZoomOverlayItem({ scale, customization }: OverlayItemProps) {
className="overlay-item flex flex-row"
style={{ color: (customization && customization.color) || undefined }}
>
<span className="mr-1 shrink-0">Zoom:</span>
<span className="mr-0.5 shrink-0 opacity-[0.67]">Zoom:</span>
<span>{scale.toFixed(2)}x</span>
</div>
);
@@ -428,7 +428,7 @@ function InstanceNumberOverlayItem({
<span>
{instanceNumber !== undefined && instanceNumber !== null ? (
<>
<span className="mr-1 shrink-0">I:</span>
<span className="mr-0.5 shrink-0 opacity-[0.67]">I:</span>
<span>{`${instanceNumber} (${imageIndex + 1}/${numberOfSlices})`}</span>
</>
) : (
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { Enums, VolumeViewport3D, utilities as csUtils } from '@cornerstonejs/core';
import { ImageScrollbar } from '@ohif/ui';
import { ImageScrollbar } from '@ohif/ui-next';
function CornerstoneImageScrollbar({
viewportData,
@@ -3,19 +3,18 @@
--marker-height: 100px;
--scrollbar-width: 20px;
pointer-events: none;
font-size: 15px;
line-height: 18px;
}
.ViewportOrientationMarkers .orientation-marker {
position: absolute;
}
.ViewportOrientationMarkers .top-mid {
top: 0.6rem;
top: 0.38rem;
left: 50%;
}
.ViewportOrientationMarkers .left-mid {
top: 47%;
left: 5px;
left: 0.38rem;
}
.ViewportOrientationMarkers .right-mid {
top: 47%;
@@ -119,8 +119,8 @@ function ViewportOrientationMarkers({
className={classNames(
'overlay-text',
`${m}-mid orientation-marker`,
'text-aqua-pale',
'text-[13px]',
'text-highlight/65',
'text-base',
'leading-5'
)}
key={`${m}-mid orientation-marker`}
+437 -52
View File
@@ -10,10 +10,12 @@ import {
ToolGroupManager,
Enums,
utilities as cstUtils,
ReferenceLinesTool,
annotation,
Types as ToolTypes,
} from '@cornerstonejs/tools';
import * as cornerstoneTools from '@cornerstonejs/tools';
import * as labelmapInterpolation from '@cornerstonejs/labelmap-interpolation';
import { ONNXSegmentationController } from '@cornerstonejs/ai';
import { Types as OhifTypes, utils } from '@ohif/core';
import i18n from '@ohif/i18n';
@@ -31,15 +33,59 @@ import toggleVOISliceSync from './utils/toggleVOISliceSync';
import { usePositionPresentationStore, useSegmentationPresentationStore } from './stores';
import { toolNames } from './initCornerstoneTools';
import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm';
import { updateSegmentBidirectionalStats } from './utils/updateSegmentationStats';
import { generateSegmentationCSVReport } from './utils/generateSegmentationCSVReport';
import { getUpdatedViewportsForSegmentation } from './utils/hydrationUtils';
const { DefaultHistoryMemo } = csUtils.HistoryMemo;
const toggleSyncFunctions = {
imageSlice: toggleImageSliceSync,
voi: toggleVOISliceSync,
};
const { segmentation: segmentationUtils } = cstUtils;
const getLabelmapTools = ({ toolGroupService }) => {
const labelmapTools = [];
const toolGroupIds = toolGroupService.getToolGroupIds();
toolGroupIds.forEach(toolGroupId => {
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId);
const tools = toolGroup.getToolInstances();
// tools is an object with toolName as the key and tool as the value
Object.keys(tools).forEach(toolName => {
const tool = tools[toolName];
if (tool instanceof cornerstoneTools.LabelmapBaseTool) {
labelmapTools.push(tool);
}
});
});
return labelmapTools;
};
const segmentAI = new ONNXSegmentationController({
autoSegmentMode: true,
models: {
sam_b: [
{
name: 'sam-b-encoder',
url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.encoder-fp16.onnx',
size: 180,
key: 'encoder',
},
{
name: 'sam-b-decoder',
url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.decoder.onnx',
size: 17,
key: 'decoder',
},
],
},
modelName: 'sam_b',
});
let segmentAIEnabled = false;
function commandsModule({
servicesManager,
extensionManager,
commandsManager,
}: OhifTypes.Extensions.ExtensionParams): OhifTypes.Extensions.CommandsModule {
const {
@@ -54,9 +100,9 @@ function commandsModule({
colorbarService,
hangingProtocolService,
syncGroupService,
} = servicesManager.services;
const { measurementServiceSource } = this;
segmentationService,
displaySetService,
} = servicesManager.services as AppTypes.Services;
function _getActiveViewportEnabledElement() {
return getActiveViewportEnabledElement(viewportGridService);
@@ -67,7 +113,85 @@ function commandsModule({
return toolGroupService.getToolGroupForViewport(viewport.id);
}
function _getActiveSegmentationInfo() {
const viewportId = viewportGridService.getActiveViewportId();
const activeSegmentation = segmentationService.getActiveSegmentation(viewportId);
const segmentationId = activeSegmentation?.segmentationId;
const activeSegmentIndex = segmentationService.getActiveSegment(viewportId).segmentIndex;
return {
segmentationId,
segmentIndex: activeSegmentIndex,
};
}
const actions = {
runSegmentBidirectional: async ({ segmentationId, segmentIndex } = {}) => {
// Get active segmentation if not specified
const targetSegmentation =
segmentationId && segmentIndex
? { segmentationId, segmentIndex }
: _getActiveSegmentationInfo();
const { segmentationId: targetId, segmentIndex: targetIndex } = targetSegmentation;
// Get bidirectional measurement data
const bidirectionalData = await cstUtils.segmentation.getSegmentLargestBidirectional({
segmentationId: targetId,
segmentIndices: [targetIndex],
});
const activeViewportId = viewportGridService.getActiveViewportId();
// Process each bidirectional measurement
bidirectionalData.forEach(measurement => {
const { segmentIndex, majorAxis, minorAxis } = measurement;
// Create annotation
const annotation = cornerstoneTools.SegmentBidirectionalTool.hydrate(
activeViewportId,
[majorAxis, minorAxis],
{
segmentIndex,
segmentationId: targetId,
}
);
measurement.annotationUID = annotation.annotationUID;
// Update segmentation stats
const updatedSegmentation = updateSegmentBidirectionalStats({
segmentationId: targetId,
segmentIndex: targetIndex,
bidirectionalData: measurement,
segmentationService,
annotation,
});
// Save changes if needed
if (updatedSegmentation) {
segmentationService.addOrUpdateSegmentation({
segmentationId: targetId,
segments: updatedSegmentation.segments,
});
}
});
// get the active segmentIndex bidirectional annotation and jump to it
const activeBidirectional = bidirectionalData.find(
measurement => measurement.segmentIndex === targetIndex
);
commandsManager.run('jumpToMeasurement', {
uid: activeBidirectional.annotationUID,
});
},
interpolateLabelmap: () => {
const { segmentationId, segmentIndex } = _getActiveSegmentationInfo();
labelmapInterpolation.interpolate({
segmentationId,
segmentIndex,
});
},
/**
* Generates the selector props for the context menu, specific to
* the cornerstone viewport, and then runs the context menu.
@@ -126,6 +250,7 @@ function commandsModule({
viewportId,
displaySetInstanceUID,
referencedImageId,
options,
}) => {
const presentations = cornerstoneViewportService.getPresentations(viewportId);
const { positionPresentationStore, setPositionPresentation, getPositionPresentationId } =
@@ -137,16 +262,18 @@ function commandsModule({
([key, value]) => key.includes(displaySetInstanceUID) && value.viewportId === viewportId
)?.[0];
if (previousReferencedDisplaySetStoreKey) {
const presentationData = referencedImageId
? {
...presentations.positionPresentation,
viewReference: {
referencedImageId,
},
}
: presentations.positionPresentation;
// Create presentation data with referencedImageId and options if provided
const presentationData = referencedImageId
? {
...presentations.positionPresentation,
viewReference: {
referencedImageId,
...options,
},
}
: presentations.positionPresentation;
if (previousReferencedDisplaySetStoreKey) {
setPositionPresentation(previousReferencedDisplaySetStoreKey, presentationData);
return;
}
@@ -154,13 +281,12 @@ function commandsModule({
// if not found means we have not visited that referencedDisplaySetInstanceUID before
// so we need to grab the positionPresentationId directly from the store,
// Todo: this is really hacky, we should have a better way for this
const positionPresentationId = getPositionPresentationId({
displaySetInstanceUIDs: [displaySetInstanceUID],
viewportId,
});
setPositionPresentation(positionPresentationId, presentations.positionPresentation);
setPositionPresentation(positionPresentationId, presentationData);
},
getNearbyToolData({ nearbyToolData, element, canvasCoordinates }) {
return nearbyToolData ?? cstUtils.getAnnotationNearPoint(element, canvasCoordinates);
@@ -191,12 +317,6 @@ function commandsModule({
? nearbyToolData
: null;
},
/** Delete the given measurement */
deleteMeasurement: ({ uid }) => {
if (uid) {
measurementServiceSource.remove(uid);
}
},
/**
* Common logic for handling measurement label updates through dialog
* @param uid - measurement uid
@@ -345,25 +465,26 @@ function commandsModule({
},
removeMeasurement: ({ uid }) => {
measurementService.remove(uid);
if (Array.isArray(uid)) {
measurementService.removeMany(uid);
} else {
measurementService.remove(uid);
}
},
toggleLockMeasurement: ({ uid }) => {
measurementService.toggleLockMeasurement(uid);
},
toggleVisibilityMeasurement: ({ uid }) => {
measurementService.toggleVisibilityMeasurement(uid);
},
/**
* Clear the measurements
*/
clearMeasurements: options => {
const { measurementFilter } = options;
measurementService.clearMeasurements(
measurementFilter ? measurementFilter.bind(options) : null
);
toggleVisibilityMeasurement: ({ uid, items, visibility }) => {
if (visibility === undefined && items?.length) {
visibility = !items[0].isVisible;
}
if (Array.isArray(uid)) {
measurementService.toggleVisibilityMeasurementMany(uid, visibility);
} else {
measurementService.toggleVisibilityMeasurement(uid, visibility);
}
},
/**
@@ -373,6 +494,43 @@ function commandsModule({
utils.downloadCSVReport(measurementService.getMeasurements(measurementFilter));
},
downloadCSVSegmentationReport: ({ segmentationId }) => {
const segmentation = segmentationService.getSegmentation(segmentationId);
const { representationData } = segmentation;
const { Labelmap } = representationData;
const { referencedImageIds } = Labelmap;
const firstImageId = referencedImageIds[0];
// find displaySet for firstImageId
const displaySet = displaySetService
.getActiveDisplaySets()
.find(ds => ds.imageIds?.some(i => i === firstImageId));
const {
SeriesNumber,
SeriesInstanceUID,
StudyInstanceUID,
SeriesDate,
SeriesTime,
SeriesDescription,
} = displaySet;
const additionalInfo = {
reference: {
SeriesNumber,
SeriesInstanceUID,
StudyInstanceUID,
SeriesDate,
SeriesTime,
SeriesDescription,
},
};
generateSegmentationCSVReport(segmentation, additionalInfo);
},
// Retrieve value commands
getActiveViewportEnabledElement: _getActiveViewportEnabledElement,
@@ -385,16 +543,18 @@ function commandsModule({
viewportGridService.setActiveViewportId(viewportId);
},
arrowTextCallback: ({ callback }) => {
arrowTextCallback: async ({ callback }) => {
const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
callInputDialogAutoComplete({
const value = await callInputDialogAutoComplete({
uiDialogService,
labelConfig,
renderContent,
});
callback?.(value);
},
toggleCine: () => {
const { viewports } = viewportGridService.getState();
const { isCineEnabled } = cineService.getState();
@@ -421,7 +581,6 @@ function commandsModule({
});
viewport.render();
},
toggleViewportColorbar: ({ viewportId, displaySetInstanceUIDs, options = {} }) => {
const hasColorbar = colorbarService.hasColorbar(viewportId);
if (hasColorbar) {
@@ -430,7 +589,6 @@ function commandsModule({
}
colorbarService.addColorbar(viewportId, displaySetInstanceUIDs, options);
},
setWindowLevel(props) {
const { toolGroupId } = props;
const { viewportId } = _getActiveViewportEnabledElement();
@@ -750,15 +908,17 @@ function commandsModule({
const options = { imageIndex: jumpIndex };
csUtils.jumpToSlice(viewport.element, options);
},
scroll: ({ direction }) => {
scroll: (options: ToolTypes.ScrollOptions) => {
const enabledElement = _getActiveViewportEnabledElement();
// Allow either or direction for consistency in scroll implementation
options.delta ??= options.direction || 1;
options.direction ??= options.delta;
if (!enabledElement) {
return;
}
const { viewport } = enabledElement;
const options = { delta: direction };
csUtils.scroll(viewport, options);
},
@@ -851,7 +1011,7 @@ function commandsModule({
});
}
},
setSourceViewportForReferenceLinesTool: ({ viewportId }) => {
setViewportForToolConfiguration: ({ viewportId, toolName }) => {
if (!viewportId) {
const { activeViewportId } = viewportGridService.getState();
viewportId = activeViewportId ?? 'default';
@@ -859,9 +1019,15 @@ function commandsModule({
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
if (!toolGroup.hasTool(toolName)) {
return;
}
const prevConfig = toolGroup?.getToolConfiguration(toolName);
toolGroup?.setToolConfiguration(
ReferenceLinesTool.toolName,
toolName,
{
...prevConfig,
sourceViewportId: viewportId,
},
true // overwrite
@@ -1094,7 +1260,12 @@ function commandsModule({
* @param props.segmentIndex - The index of the segment to activate
*/
setActiveSegmentAndCenterCommand: ({ segmentationId, segmentIndex }) => {
const { segmentationService } = servicesManager.services;
const { segmentationService, viewportGridService } = servicesManager.services;
// set both active segmentation and active segment
segmentationService.setActiveSegmentation(
viewportGridService.getActiveViewportId(),
segmentationId
);
segmentationService.setActiveSegment(segmentationId, segmentIndex);
segmentationService.jumpToSegmentCenter(segmentationId, segmentIndex);
},
@@ -1356,18 +1527,220 @@ function commandsModule({
viewportGridService.getActiveViewportId()
);
},
deleteActiveAnnotation: () => {
const activeAnnotationsUID = cornerstoneTools.annotation.selection.getAnnotationsSelected();
activeAnnotationsUID.forEach(activeAnnotationUID => {
measurementService.remove(activeAnnotationUID);
});
},
setDisplaySetsForViewports: ({ viewportsToUpdate }) => {
const { cineService, viewportGridService } = servicesManager.services;
// Stopping the cine of modified viewports before changing the viewports to
// avoid inconsistent state and lost references
viewportsToUpdate.forEach(viewport => {
const state = cineService.getState();
const currentCineState = state.cines?.[viewport.viewportId];
cineService.setCine({
id: viewport.viewportId,
frameRate: currentCineState?.frameRate ?? state.default?.frameRate ?? 24,
isPlaying: false,
});
});
viewportGridService.setDisplaySetsForViewports(viewportsToUpdate);
},
undo: () => {
DefaultHistoryMemo.undo();
},
redo: () => {
DefaultHistoryMemo.redo();
},
toggleSegmentPreviewEdit: ({ toggle }) => {
let labelmapTools = getLabelmapTools({ toolGroupService });
labelmapTools = labelmapTools.filter(tool => !tool.toolName.includes('Eraser'));
labelmapTools.forEach(tool => {
tool.configuration = {
...tool.configuration,
preview: {
...tool.configuration.preview,
enabled: toggle,
},
};
});
},
toggleSegmentSelect: ({ toggle }) => {
const toolGroupIds = toolGroupService.getToolGroupIds();
toolGroupIds.forEach(toolGroupId => {
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId);
if (toggle) {
toolGroup.setToolActive(cornerstoneTools.SegmentSelectTool.toolName);
} else {
toolGroup.setToolDisabled(cornerstoneTools.SegmentSelectTool.toolName);
}
});
},
toggleUseCenterSegmentIndex: ({ toggle }) => {
let labelmapTools = getLabelmapTools({ toolGroupService });
labelmapTools = labelmapTools.filter(tool => !tool.toolName.includes('Eraser'));
labelmapTools.forEach(tool => {
tool.configuration = {
...tool.configuration,
useCenterSegmentIndex: toggle,
};
});
},
_handlePreviewAction: action => {
const labelmapTools = getLabelmapTools({ toolGroupService });
const { viewport } = _getActiveViewportEnabledElement();
const activeTools = labelmapTools.filter(
tool => tool.mode === 'Active' || tool.mode === 'Enabled'
);
activeTools.forEach(tool => {
tool[`${action}Preview`]();
});
if (segmentAI.enabled) {
segmentAI[`${action}Preview`](viewport.element);
}
},
acceptPreview: () => {
actions._handlePreviewAction('accept');
},
rejectPreview: () => {
actions._handlePreviewAction('reject');
},
clearMarkersForMarkerLabelmap: () => {
const { viewport } = _getActiveViewportEnabledElement();
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroupForViewport(viewport.id);
const toolInstance = toolGroup.getToolInstance('MarkerLabelmap');
if (!toolInstance) {
return;
}
toolInstance.clearMarkers(viewport);
},
interpolateScrollForMarkerLabelmap: () => {
const { viewport } = _getActiveViewportEnabledElement();
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroupForViewport(viewport.id);
const toolInstance = toolGroup.getToolInstance('MarkerLabelmap');
if (!toolInstance) {
return;
}
toolInstance.interpolateScroll(viewport, 1);
},
toggleLabelmapAssist: async () => {
const { viewport } = _getActiveViewportEnabledElement();
const newState = !segmentAI.enabled;
segmentAI.enabled = newState;
if (!segmentAIEnabled) {
await segmentAI.initModel();
segmentAIEnabled = true;
}
// set the brush tool to active
const toolGroupIds = toolGroupService.getToolGroupIds();
if (newState) {
actions.setToolActiveToolbar({
toolName: 'CircularBrushForAutoSegmentAI',
toolGroupIds: toolGroupIds,
});
} else {
toolGroupIds.forEach(toolGroupId => {
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId);
toolGroup.setToolPassive('CircularBrushForAutoSegmentAI');
});
}
if (segmentAI.enabled) {
segmentAI.initViewport(viewport);
}
},
setBrushSize: ({ value, toolNames }) => {
const brushSize = Number(value);
toolGroupService.getToolGroupIds()?.forEach(toolGroupId => {
if (toolNames?.length === 0) {
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize);
} else {
toolNames?.forEach(toolName => {
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize, toolName);
});
}
});
},
setThresholdRange: ({
value,
toolNames = [
'ThresholdCircularBrush',
'ThresholdSphereBrush',
'ThresholdCircularBrushDynamic',
'ThresholdSphereBrushDynamic',
],
}) => {
const toolGroupIds = toolGroupService.getToolGroupIds();
if (!toolGroupIds?.length) {
return;
}
for (const toolGroupId of toolGroupIds) {
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
toolNames?.forEach(toolName => {
toolGroup.setToolConfiguration(toolName, {
threshold: {
range: value,
},
});
});
}
},
increaseBrushSize: () => {
const toolGroupIds = toolGroupService.getToolGroupIds();
if (!toolGroupIds?.length) {
return;
}
for (const toolGroupId of toolGroupIds) {
const brushSize = segmentationUtils.getBrushSizeForToolGroup(toolGroupId);
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize + 3);
}
},
decreaseBrushSize: () => {
const toolGroupIds = toolGroupService.getToolGroupIds();
if (!toolGroupIds?.length) {
return;
}
for (const toolGroupId of toolGroupIds) {
const brushSize = segmentationUtils.getBrushSizeForToolGroup(toolGroupId);
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, brushSize - 3);
}
},
addNewSegment: () => {
const { segmentationService } = servicesManager.services;
const { activeViewportId } = viewportGridService.getState();
const activeSegmentation = segmentationService.getActiveSegmentation(activeViewportId);
segmentationService.addSegment(activeSegmentation.segmentationId);
},
loadSegmentationDisplaySetsForViewport: ({ viewportId, displaySetInstanceUIDs }) => {
const updatedViewports = getUpdatedViewportsForSegmentation({
viewportId,
servicesManager,
displaySetInstanceUIDs,
});
updatedViewports.forEach(viewport => {
viewportGridService.setDisplaySetsForViewport({
viewportId: viewport.viewportId,
displaySetInstanceUIDs: viewport.displaySetInstanceUIDs,
});
});
},
};
const definitions = {
@@ -1396,9 +1769,6 @@ function commandsModule({
toggleViewportColorbar: {
commandFn: actions.toggleViewportColorbar,
},
deleteMeasurement: {
commandFn: actions.deleteMeasurement,
},
setMeasurementLabel: {
commandFn: actions.setMeasurementLabel,
},
@@ -1408,9 +1778,6 @@ function commandsModule({
updateMeasurement: {
commandFn: actions.updateMeasurement,
},
clearMeasurements: {
commandFn: actions.clearMeasurements,
},
jumpToMeasurement: {
commandFn: actions.jumpToMeasurement,
},
@@ -1517,8 +1884,8 @@ function commandsModule({
setViewportColormap: {
commandFn: actions.setViewportColormap,
},
setSourceViewportForReferenceLinesTool: {
commandFn: actions.setSourceViewportForReferenceLinesTool,
setViewportForToolConfiguration: {
commandFn: actions.setViewportForToolConfiguration,
},
storePresentation: {
commandFn: actions.storePresentation,
@@ -1634,8 +2001,26 @@ function commandsModule({
deleteActiveAnnotation: {
commandFn: actions.deleteActiveAnnotation,
},
setDisplaySetsForViewports: actions.setDisplaySetsForViewports,
undo: actions.undo,
redo: actions.redo,
interpolateLabelmap: actions.interpolateLabelmap,
runSegmentBidirectional: actions.runSegmentBidirectional,
downloadCSVSegmentationReport: actions.downloadCSVSegmentationReport,
toggleSegmentPreviewEdit: actions.toggleSegmentPreviewEdit,
toggleSegmentSelect: actions.toggleSegmentSelect,
acceptPreview: actions.acceptPreview,
rejectPreview: actions.rejectPreview,
toggleUseCenterSegmentIndex: actions.toggleUseCenterSegmentIndex,
toggleLabelmapAssist: actions.toggleLabelmapAssist,
interpolateScrollForMarkerLabelmap: actions.interpolateScrollForMarkerLabelmap,
clearMarkersForMarkerLabelmap: actions.clearMarkersForMarkerLabelmap,
setBrushSize: actions.setBrushSize,
setThresholdRange: actions.setThresholdRange,
increaseBrushSize: actions.increaseBrushSize,
decreaseBrushSize: actions.decreaseBrushSize,
addNewSegment: actions.addNewSegment,
loadSegmentationDisplaySetsForViewport: actions.loadSegmentationDisplaySetsForViewport,
};
return {
@@ -0,0 +1,195 @@
import React from 'react';
import { useSystem } from '@ohif/core';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@ohif/ui-next';
import { ChevronDownIcon } from '@radix-ui/react-icons';
export type AccordionGrouping = {
[name: string]: unknown;
};
export type AccordionGroupProps = {
grouping: AccordionGrouping;
};
/**
* Searches for the required type from the provided allChildren list and
* renders them.
*/
export const CloneChildren = props => {
const { group, allChildren, children, childType, defaultTypes } = props;
const subType = group?.subType;
for (const child of allChildren) {
if (subType && child.props?.subType !== subType) {
continue;
}
if (childType && child.type === childType) {
return React.cloneElement(child, { ...props, children: child.props.children });
}
if (defaultTypes?.indexOf(child.type) === -1) {
return childType({ ...props, children: child });
}
}
if (!children) {
throw new Error(`No children defined for ${props.name} CloneChildren in group ${group?.name}`);
}
return React.cloneElement(children, props);
};
/** Used to exclude defaults */
const DEFAULT_TYPES = [GroupAccordion, Content, Trigger];
/**
* An AccordionGroup is a component that splits a set of items into different
* groups according to a set of grouping rules. It then puts the groups
* into a set of accordion folds selected from the body of the accordion group,
* looking for matching trigger/content sections according to the type definition
* in the group with first one found being used.
*
* This design allows for easy customization of the component by declaring grouping
* functions with default grouping setups and then only overriding the specific
* children needing to be changed. See the PanelMeasurement for some example
* possibilities of how to modify the default grouping, or the test-extension
* measurements panel for a practical, working example.
*/
export function AccordionGroup(props) {
const { grouping, items, children, sourceChildren, type } = props;
const childProps = useSystem();
let defaultValue = props.defaultValue;
const groups = grouping.groupingFunction(items, grouping, childProps);
if (!defaultValue) {
const defaultGroup = groups.values().find(group => group.isSelected);
defaultValue = defaultGroup?.key || defaultGroup?.title;
}
const valueArr =
(Array.isArray(defaultValue) && defaultValue) || (defaultValue && [defaultValue]) || [];
const sourceChildrenArr = sourceChildren ? React.Children.toArray(sourceChildren) : [];
const childrenArr = children ? React.Children.toArray(children) : [];
const allChildren = sourceChildrenArr.concat(childrenArr);
return (
<CloneChildren
allChildren={allChildren}
groups={groups}
childType={GroupAccordion}
grouping={grouping}
defaultValue={valueArr}
name={'grouping ' + grouping.name}
>
<DefaultAccordion name="DefaultAccordion" />
</CloneChildren>
);
}
function DefaultAccordion(props) {
const { groups, defaultValue, grouping, allChildren, asChild } = props;
if (!allChildren || !groups) {
return null;
}
if (Boolean(asChild)) {
return React.cloneElement(props.children, props);
}
return (
<Accordion
type={grouping.type || 'multiple'}
className="text-white"
defaultValue={defaultValue}
>
{[...groups.entries()].map(([key, group]) => {
return (
<AccordionItem
key={group.key + '-i'}
value={group.key}
>
<CloneChildren
allChildren={allChildren}
group={group}
childType={Trigger}
name="AccordionGroup.Trigger"
/>
<CloneChildren
allChildren={allChildren}
group={group}
childType={Content}
defaultTypes={DEFAULT_TYPES}
name="AccordionGroup.Content"
/>
</AccordionItem>
);
})}
</Accordion>
);
}
function GroupAccordion(props) {
const { groups, children } = props;
if (!groups) {
return null;
}
return [...groups.values()].map(group =>
React.cloneElement(children, {
...props,
children: children.props.children,
group,
...group,
key: group.title,
})
);
}
function Content(props) {
const { children, asChild, ...childProps } = props;
const { group } = props;
Object.assign(childProps, group);
if (!group) {
return null;
}
if (asChild) {
return React.cloneElement(children, { ...group, ...props, children: children.props.children });
}
return (
<AccordionContent>
{React.cloneElement(children, { ...group, ...props, children: children.props.children })}
</AccordionContent>
);
}
function Trigger(props) {
const { children, asChild, ...childProps } = props;
const { group } = props;
Object.assign(childProps, group);
if (!group) {
return null;
}
if (asChild) {
return React.cloneElement(children, childProps);
}
return (
<AccordionTrigger
value={group.value}
asChild={true}
>
<div>
{React.cloneElement(children, childProps)}
<ChevronDownIcon
key="chevronDown"
className="text-primary h-4 w-4 shrink-0 transition-transform duration-200"
/>
</div>
</AccordionTrigger>
);
}
AccordionGroup.Content = Content;
AccordionGroup.Trigger = Trigger;
AccordionGroup.Accordion = GroupAccordion;
export default AccordionGroup;
@@ -0,0 +1,4 @@
export * from './AccordionGroup';
import AccordionGroup from './AccordionGroup';
export default AccordionGroup;
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState, useRef } from 'react';
import { useCine } from '@ohif/ui';
import { useCine } from '@ohif/ui-next';
import { Enums, eventTarget, cache } from '@cornerstonejs/core';
import { useAppConfig } from '@state';
@@ -244,4 +244,4 @@ function RenderCinePlayer({
);
}
export default WrappedCinePlayer;
export default WrappedCinePlayer;
@@ -303,7 +303,7 @@ function DicomUploadProgress({
<span
className={classNames(
NO_WRAP_ELLIPSIS_CLASS_NAMES,
'text-primary-active hover:text-primary-light active:text-aqua-pale ml-auto cursor-pointer'
'text-primary hover:text-primary-light active:text-aqua-pale ml-auto cursor-pointer'
)}
onClick={cancelAllUploads}
>
@@ -89,7 +89,7 @@ const DicomUploadProgressItem = memo(
)}
<div className="ml-auto flex cursor-pointer">
<Icons.Close
className="text-primary-active self-center"
className="text-primary self-center"
onClick={cancelUpload}
/>
</div>
@@ -0,0 +1,70 @@
import React from 'react';
import { Accordion, AccordionContent, AccordionItem } from '@ohif/ui-next';
import PanelAccordionTrigger from './PanelAccordionTrigger';
import MeasurementsMenu from './MeasurementsMenu';
import { useSystem } from '@ohif/core';
export function MeasurementItem(props) {
const { index, item } = props;
return (
<PanelAccordionTrigger
count={index + 1}
text={item.toolName || item.label || item.title}
colorHex="#f00"
isActive={item.isSelected}
menu={MeasurementsMenu}
group={{ items: [item], onClick: props.onClick }}
/>
);
}
export default function MeasurementAccordion(props) {
const { items } = props;
const system = useSystem();
const onClick = (e, group) => {
const { items } = group;
// Just jump to the first measurement in the set, and mark that one as active
// with the set of items.
system.commandsManager.run('jumpToMeasurement', {
uid: items[0].uid,
displayMeasurements: items,
group,
});
};
return (
<Accordion
type="multiple"
className="flex-shrink-0 overflow-hidden"
>
{items.map((item, index) => {
const { displayText: details = {} } = item;
return (
<AccordionItem
key={`measurementAccordion:${item.uid}`}
value={item.uid}
>
<MeasurementItem
item={item}
key={`measurementItem:${item.uid}`}
index={index}
onClick={onClick}
/>
<AccordionContent key={`measurementContent:${item.uid}`}>
<div className="ml-7 px-2 py-2">
<div className="text-secondary-foreground flex items-center gap-1 text-base leading-normal">
{details.primary?.length > 0 &&
details.primary.map((detail, index) => (
<span key={`details:${item.uid}:${index}`}>{detail}</span>
))}
</div>
</div>
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
);
}
@@ -0,0 +1,30 @@
import React from 'react';
import { MeasurementTable } from '@ohif/ui-next';
import { useSystem } from '@ohif/core';
/**
* This is a measurement table that is designed to be nested inside
* the accordion groups.
*/
export default function MeasurementTableNested(props) {
const { title, items, group, customHeader } = props;
const { commandsManager } = useSystem();
const onAction = (e, command, uid) => {
commandsManager.run(command, { uid, annotationUID: uid, displayMeasurements: items });
};
return (
<MeasurementTable
title={title ? title : `Measurements`}
data={items}
onAction={onAction}
{...group}
key={group.key}
>
<MeasurementTable.Header key="measurementTableHeader">
{customHeader && group.isFirst && customHeader({ ...props, items: props.allItems })}
</MeasurementTable.Header>
<MeasurementTable.Body key="measurementTableBody" />
</MeasurementTable>
);
}
@@ -0,0 +1,81 @@
import React, { useState } from 'react';
import { useSystem } from '@ohif/core';
import {
Button,
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
Icons,
} from '@ohif/ui-next';
export function MeasumentsMenu(props) {
const { group, classNames } = props;
if (!group.items?.length) {
console.log('No items to iterate', group.items);
return null;
}
const { items } = group;
const [item] = items;
const { isSelected, isVisible } = item;
const system = useSystem();
const onAction = (event, command, args?) => {
const uid = items.map(item => item.uid);
// Some commands use displayMeasurements and some use items
system.commandsManager.run(command, {
...args,
uid,
displayMeasurements: items,
items,
event,
});
};
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
return (
<div className={`relative ml-2 inline-flex items-center space-x-1 ${classNames}`}>
{/* Visibility Toggle Icon */}
<Button
size="icon"
variant="ghost"
className={`h-6 w-6 transition-opacity ${
isSelected || !isVisible ? 'opacity-100' : 'opacity-50 group-hover:opacity-100'
}`}
aria-label={isVisible ? 'Hide' : 'Show'}
onClick={e => {
e.stopPropagation();
onAction(e, ['jumpToMeasurement', 'toggleVisibilityMeasurement']);
}}
>
{isVisible ? <Icons.Hide className="h-6 w-6" /> : <Icons.Show className="h-6 w-6" />}
</Button>
{/* Actions Dropdown Menu */}
<DropdownMenu onOpenChange={open => setIsDropdownOpen(open)}>
<DropdownMenuTrigger asChild>
<Button
size="icon"
variant="ghost"
className={`h-6 w-6 transition-opacity ${
isSelected || isDropdownOpen ? 'opacity-100' : 'opacity-50 group-hover:opacity-100'
}`}
aria-label="Actions"
onClick={e => e.stopPropagation()} // Prevent row selection on button click
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={e => onAction(e, 'removeMeasurement')}>
<Icons.Delete className="text-foreground" />
<span className="pl-2">Delete</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}
export default MeasumentsMenu;
@@ -0,0 +1,82 @@
import React from 'react';
import AccordionGroup from './AccordionGroup';
import { utils } from '@ohif/core';
import MeasurementTableNested from './MeasurementTableNested';
const { filterNot, filterAdditionalFindings } = utils.MeasurementFilters;
export const MeasurementOrAdditionalFindingSets = [
{
title: 'Measurements',
filter: filterNot(filterAdditionalFindings),
},
{
title: 'Additional Findings',
filter: filterAdditionalFindings,
},
];
/**
* Groups measurements by study in order to allow display and saving by study
* @param {Object} servicesManager
*/
export const groupByNamedSets = (items, grouping) => {
const groups = new Map();
const { namedSets } = grouping;
for (const namedSet of namedSets) {
const name = namedSet.id || namedSet.title;
groups.set(name, {
...grouping,
...namedSet,
items: [],
isFirst: groups.size === 0,
title: name,
key: name,
});
}
items.forEach(item => {
for (const namedSet of namedSets) {
if (namedSet.filter(item)) {
const name = namedSet.id || namedSet.title;
groups.get(name).items.push(item);
return;
}
}
});
for (const namedSet of namedSets) {
const name = namedSet.id || namedSet.title;
if (!groups.get(name).items.length) {
groups.delete(name);
}
}
return groups;
};
export function MeasurementsOrAdditionalFindings(props): React.ReactNode {
const { items, children, grouping = {}, customHeader, group, actions } = props;
return (
<AccordionGroup
grouping={{
groupingFunction: groupByNamedSets,
name: 'measurementsOrAdditional',
namedSets: MeasurementOrAdditionalFindingSets,
StudyInstanceUID: group?.StudyInstanceUID,
...grouping,
}}
items={items}
sourceChildren={children}
>
<AccordionGroup.Accordion noWrapper="true">
<MeasurementTableNested
customHeader={customHeader}
allItems={items}
actions={actions}
/>
</AccordionGroup.Accordion>
</AccordionGroup>
);
}
export default MeasurementsOrAdditionalFindings;
@@ -0,0 +1,48 @@
import React from 'react';
import { AccordionTrigger, ColorCircle } from '@ohif/ui-next';
import { ChevronDownIcon } from '@radix-ui/react-icons';
function onClickDefault(e) {
const { group, onClick = group?.onClick } = this;
if (!onClick) {
console.log('No onClick function', group);
return;
}
console.log('onClickDefault');
e.preventDefault();
e.stopPropagation();
onClick(e, group);
return false;
}
export default function PanelAccordionTrigger(props) {
const { marginLeft = 8, isActive = false, colorHex, count, text, menu: Menu = null } = props;
return (
<AccordionTrigger
style={{ marginLeft: `${marginLeft}px`, padding: 0 }}
asChild={true}
>
<div className={`inline-flex text-base ${isActive ? 'bg-popover' : 'bg-muted'} flex-grow`}>
<button onClick={onClickDefault.bind(props)}>
<span
className={`inline-flex rounded-l border-r border-black ${isActive ? 'bg-highlight' : 'bg-muted'}`}
>
{count !== undefined ? <span className="px-2">{count}</span> : null}
{colorHex && <ColorCircle colorHex={colorHex} />}
</span>
<span>{text}</span>
</button>
{Menu && (
<Menu
{...props}
classNames="justify-end flex-grow"
/>
)}
<ChevronDownIcon className="text-primary h-4 w-4 shrink-0 transition-transform duration-200" />
</div>
</AccordionTrigger>
);
}
@@ -0,0 +1,90 @@
import React from 'react';
import { useActiveViewportDisplaySets, useSystem } from '@ohif/core';
import AccordionGroup from './AccordionGroup';
import PanelAccordionTrigger from './PanelAccordionTrigger';
import MeasurementItems from './MeasurementItems';
import MeasurementsMenu from './MeasurementsMenu';
/**
* Groups measurements by study in order to allow display and saving by study
* @param {Object} servicesManager
*/
export const groupByDisplaySet = (items, grouping, childProps) => {
const groups = new Map();
const { displaySetService } = childProps.servicesManager.services;
const { activeDisplaySetInstanceUID } = grouping;
items.forEach(item => {
const { displaySetInstanceUID } = item;
if (!groups.has(displaySetInstanceUID)) {
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
groups.set(displaySetInstanceUID, {
header: null,
isSelected: displaySetInstanceUID == activeDisplaySetInstanceUID,
...grouping,
items: [],
key: displaySetInstanceUID,
title: 'Series Measurements',
displaySet,
});
}
groups.get(displaySetInstanceUID).items.push(item);
});
return groups;
};
export function SeriesMeasurementTrigger(props) {
const { group, isSelected, displaySet, menu } = props;
const { SeriesNumber = 1, SeriesDescription } = displaySet;
return (
<PanelAccordionTrigger
text={`Series #${SeriesNumber} ${SeriesDescription}`}
count={group.items.length}
isActive={isSelected}
group={group}
menu={menu}
marginLeft="0"
/>
);
}
export function SeriesMeasurements(props): React.ReactNode {
const { items, grouping = {}, children } = props;
const system = useSystem();
const activeDisplaySets = useActiveViewportDisplaySets(system);
const activeDisplaySetInstanceUID = activeDisplaySets?.[0]?.displaySetInstanceUID;
const onClick = (_e, group) => {
const { items } = group;
system.commandsManager.run('jumpToMeasurement', {
uid: items[0].uid,
displayMeasurements: items,
group,
});
};
// The content of the accordion group will default to the children of the
// parent declaration if present, otherwise to MeasurementItems
return (
<AccordionGroup
grouping={{
groupingFunction: groupByDisplaySet,
activeDisplaySetInstanceUID,
...grouping,
onClick,
}}
items={items}
sourceChildren={children}
>
<AccordionGroup.Trigger asChild={true}>
<SeriesMeasurementTrigger menu={MeasurementsMenu} />
</AccordionGroup.Trigger>
<MeasurementItems />
</AccordionGroup>
);
}
export default SeriesMeasurements;
@@ -0,0 +1,21 @@
import React from 'react';
import { utils } from '@ohif/core';
const { formatDate } = utils;
export function SeriesSummaryFromDisplaySet({ displaySet }) {
if (!displaySet) {
return null;
}
const { SeriesDate, SeriesDescription, SeriesNumber = 1 } = displaySet;
return (
<div className="mx-2 my-0">
<div className="text-foreground pb-1 text-sm">
Series #{SeriesNumber} {SeriesDescription}
</div>
<div className="text-muted-foreground text-sm">{formatDate(SeriesDate)}</div>
</div>
);
}
@@ -0,0 +1,88 @@
import React from 'react';
import { useActiveViewportDisplaySets, useSystem, utils } from '@ohif/core';
// import { AccordionContent, AccordionItem, AccordionTrigger } from '@ohif/ui-next';
import { AccordionGroup } from './AccordionGroup';
import MeasurementsOrAdditionalFindings from './MeasurementsOrAdditionalFindings';
import StudySummaryWithActions from './StudySummaryWithActions';
const { MeasurementFilters } = utils;
/**
* Groups measurements by study in order to allow display and saving by study
* @param {Object} servicesManager
*/
export const groupByStudy = (items, grouping, childProps) => {
const groups = new Map();
const { activeStudyUID } = grouping;
const { displaySetService } = childProps.servicesManager.services;
const getItemStudyInstanceUID = item => {
const displaySet = displaySetService.getDisplaySetByUID(item.displaySetInstanceUID);
return displaySet.instances[0].StudyInstanceUID;
};
let firstSelected, firstGroup;
items.forEach(item => {
const studyUID = getItemStudyInstanceUID(item);
if (!groups.has(studyUID)) {
const items = [];
const filter = MeasurementFilters.filterAnd(
MeasurementFilters.filterMeasurementsByStudyUID(activeStudyUID),
grouping.filter
);
const group = {
...grouping,
items,
displayMeasurements: items,
key: studyUID,
isSelected: studyUID === activeStudyUID,
StudyInstanceUID: activeStudyUID,
filter,
measurementFilter: filter,
};
if (group.isSelected && !firstSelected) {
firstSelected = group;
}
firstGroup ||= group;
groups.set(studyUID, group);
}
if (!firstSelected && firstGroup) {
firstGroup.isSelected = true;
}
const group = groups.get(studyUID);
group.items.push(item);
});
return groups;
};
export function StudyMeasurements(props): React.ReactNode {
const { items, grouping = {}, children } = props;
const system = useSystem();
const activeDisplaySets = useActiveViewportDisplaySets(system);
const activeStudyUID = activeDisplaySets?.[0]?.StudyInstanceUID;
return (
<AccordionGroup
grouping={{
name: 'groupByStudy',
groupingFunction: groupByStudy,
activeStudyUID,
...grouping,
}}
items={items}
value={[activeStudyUID]}
sourceChildren={children}
>
<AccordionGroup.Trigger>
<StudySummaryWithActions />
</AccordionGroup.Trigger>
<MeasurementsOrAdditionalFindings activeStudyUID={activeStudyUID} />
</AccordionGroup>
);
}
export default StudyMeasurements;
@@ -0,0 +1,73 @@
import React from 'react';
import { Button, Icons } from '@ohif/ui-next';
import { useSystem } from '@ohif/core';
export function StudyMeasurementsActions({ items, StudyInstanceUID, measurementFilter, actions }) {
const { commandsManager } = useSystem();
const disabled = !items?.length;
if (disabled) {
return null;
}
return (
<div className="bg-background flex h-9 w-full items-center rounded pr-0.5">
<div className="flex space-x-1">
<Button
size="sm"
variant="ghost"
className="pl-1.5"
onClick={() => {
commandsManager.runCommand('downloadCSVMeasurementsReport', {
StudyInstanceUID,
measurementFilter,
});
}}
>
<Icons.Download className="h-5 w-5" />
<span className="pl-1">CSV</span>
</Button>
<Button
size="sm"
variant="ghost"
className="pl-0.5"
onClick={e => {
e.stopPropagation();
if (actions?.createSR) {
actions.createSR({ StudyInstanceUID, measurementFilter });
return;
}
commandsManager.run('promptSaveReport', {
StudyInstanceUID,
measurementFilter,
});
}}
>
<Icons.Add />
Create SR
</Button>
<Button
size="sm"
variant="ghost"
className="pl-0.5"
onClick={e => {
e.stopPropagation();
if (actions?.onDelete) {
actions.onDelete();
return;
}
commandsManager.runCommand('clearMeasurements', {
measurementFilter,
});
}}
>
<Icons.Delete />
Delete
</Button>
</div>
</div>
);
}
export default StudyMeasurementsActions;
@@ -4,7 +4,8 @@ import { StudySummary } from '@ohif/ui-next';
const { formatDate } = utils;
export function StudySummaryFromMetadata({ StudyInstanceUID }) {
export function StudySummaryFromMetadata(props) {
const { StudyInstanceUID } = props;
if (!StudyInstanceUID) {
return null;
}
@@ -20,6 +21,6 @@ export function StudySummaryFromMetadata({ StudyInstanceUID }) {
<StudySummary
date={formatDate(StudyDate)}
description={StudyDescription}
></StudySummary>
/>
);
}
@@ -0,0 +1,14 @@
import React from 'react';
import { StudySummaryFromMetadata } from './StudySummaryFromMetadata';
import StudyMeasurementsActions from './StudyMeasurementsActions';
export function StudySummaryWithActions(props) {
return (
<div>
<StudySummaryFromMetadata {...props} />
<StudyMeasurementsActions {...props} />
</div>
);
}
export default StudySummaryWithActions;
@@ -1,7 +1,7 @@
import React, { useEffect, useCallback, useState, ReactElement, useMemo } from 'react';
import PropTypes from 'prop-types';
import debounce from 'lodash.debounce';
import { PanelSection, WindowLevel } from '@ohif/ui';
import { PanelSection, WindowLevel } from '@ohif/ui-next';
import { Enums, eventTarget } from '@cornerstonejs/core';
import { useActiveViewportDisplaySets } from '@ohif/core';
import {
@@ -20,7 +20,7 @@ const ViewportWindowLevel = ({
viewportId: string;
}>): ReactElement => {
const { cornerstoneViewportService } = servicesManager.services;
const [windowLevels, setWindowLevels] = useState([]);
const [windowLevels, setWindowLevels] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const displaySets = useActiveViewportDisplaySets({ servicesManager });
@@ -200,29 +200,36 @@ const ViewportWindowLevel = ({
}, [viewportId, cornerstoneViewportService, updateViewportHistograms, displaySetIds, isLoading]);
return (
<PanelSection title="Window Level">
{windowLevels.map((windowLevel, i) => {
if (!windowLevel.histogram) {
return null;
}
<PanelSection defaultOpen={true}>
<PanelSection.Header>Window Level</PanelSection.Header>
<PanelSection.Content className="bg-muted py-1">
{windowLevels.map((windowLevel, i) => {
if (!windowLevel.histogram) {
return null;
}
return (
<WindowLevel
key={windowLevel.volumeId}
title={`${windowLevel.modality}`}
histogram={windowLevel.histogram}
voi={windowLevel.voi}
step={windowLevel.step}
showOpacitySlider={windowLevel.showOpacitySlider}
colormap={windowLevel.colormap}
onVOIChange={voi => handleVOIChange(windowLevel.volumeId, voi)}
opacity={windowLevel.opacity}
onOpacityChange={opacity =>
handleOpacityChange(windowLevel.viewportId, i, windowLevel.volumeId, opacity)
}
/>
);
})}
return (
<WindowLevel
key={windowLevel.volumeId}
histogram={windowLevel.histogram}
voi={windowLevel.voi}
step={windowLevel.step}
showOpacitySlider={windowLevel.showOpacitySlider}
colormap={windowLevel.colormap}
onVOIChange={voi => handleVOIChange(windowLevel.volumeId, voi)}
opacity={windowLevel.opacity}
onOpacityChange={opacity =>
handleOpacityChange(windowLevel.viewportId, i, windowLevel.volumeId, opacity)
}
/>
);
})}
{windowLevels.length === 0 && !isLoading && (
<div className="text-muted-foreground py-2 text-center text-sm">
No window level data available
</div>
)}
</PanelSection.Content>
</PanelSection>
);
};
@@ -1,5 +1,5 @@
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
import { SwitchButton } from '@ohif/ui';
import { Switch } from '@ohif/ui-next';
import { StackViewport, VolumeViewport } from '@cornerstonejs/core';
import { ColorbarProps } from '../../types/Colorbar';
import { utilities } from '@cornerstonejs/core';
@@ -22,7 +22,7 @@ export function setViewportColorbar(
colorbarOptions.ticks = {
position: 'left',
style: {
font: '12px Arial',
font: '13px Inter',
color: '#000000',
maxNumTicks: 8,
tickSize: 5,
@@ -101,12 +101,20 @@ export function Colorbar({
}, [viewportId]);
return (
<div className="all-in-one-menu-item flex w-full justify-center">
<div className="mr-2 w-[28px]"></div>
<SwitchButton
label="Display Color bar"
<div
className="hover:bg-accent flex h-8 w-full flex-shrink-0 cursor-pointer items-center px-2 text-base hover:rounded"
onClick={e => {
e.stopPropagation();
onSetColorbar();
}}
>
<div className="flex w-7 flex-shrink-0 items-center justify-center"></div>
<span className="flex-grow">Display Color bar</span>
<Switch
className="ml-2 flex-shrink-0"
checked={showColorbar}
onChange={() => {
onClick={e => {
e.stopPropagation();
onSetColorbar();
}}
/>
@@ -1,5 +1,6 @@
import React, { ReactElement, useCallback, useEffect, useRef, useState, useMemo } from 'react';
import { AllInOneMenu, ButtonGroup, SwitchButton } from '@ohif/ui';
import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
import { AllInOneMenu, Switch, Tabs, TabsList, TabsTrigger } from '@ohif/ui-next';
import { StackViewport, Types } from '@cornerstonejs/core';
import { ColormapProps } from '../../types/Colormap';
@@ -64,20 +65,9 @@ export function Colormap({
return colormap;
};
const buttons = useMemo(() => {
return displaySets.map((displaySet, index) => ({
children: displaySet.Modality,
key: index,
style: {
minWidth: `calc(100% / ${displaySets.length})`,
fontSize: '0.8rem',
textAlign: 'center',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
}));
}, [displaySets]);
const activeIndex = displaySets.findIndex(
ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID
);
useEffect(() => {
setActiveDisplaySet(displaySets[displaySets.length - 1]);
@@ -85,46 +75,52 @@ export function Colormap({
return (
<>
{buttons.length > 1 && (
<div className="all-in-one-menu-item flex w-full justify-center">
<ButtonGroup
onActiveIndexChange={index => {
{displaySets.length > 1 && (
<div className="flex h-8 w-full flex-shrink-0 items-center justify-center px-2 text-base">
<Tabs
value={String(activeIndex)}
onValueChange={val => {
const index = parseInt(val, 10);
setActiveDisplaySet(displaySets[index]);
setPrePreviewColormap(null);
}}
activeIndex={
displaySets.findIndex(
ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID
) || 1
}
className="w-[70%] text-[10px]"
>
{buttons.map(({ children, key, style }) => (
<div
key={key}
style={style}
>
{children}
</div>
))}
</ButtonGroup>
<TabsList>
{displaySets.map((ds, i) => (
<TabsTrigger
key={i}
value={String(i)}
>
{ds.Modality}
</TabsTrigger>
))}
</TabsList>
</Tabs>
</div>
)}
<div className="all-in-one-menu-item flex w-full justify-center">
<SwitchButton
label="Preview in viewport"
<div
className="hover:bg-accent flex h-8 w-full flex-shrink-0 cursor-pointer items-center px-2 text-base hover:rounded"
onClick={() => setShowPreview(!showPreview)}
>
<span className="flex-shrink-0">Preview in viewport</span>
<Switch
className="ml-auto flex-shrink-0"
checked={showPreview}
onChange={checked => {
onCheckedChange={checked => {
setShowPreview(checked);
}}
/>
</div>
<AllInOneMenu.DividerItem />
<AllInOneMenu.ItemPanel>
<AllInOneMenu.ItemPanel
maxHeight="calc(100vh - 250px)"
className="min-h-[200px] flex-grow"
>
{colormaps.map((colormap, index) => (
<AllInOneMenu.Item
key={index}
label={colormap.description}
useIconSpace={false}
onClick={() => {
onSetColorLUT({
viewportId,
@@ -1,5 +1,6 @@
import React, { ReactElement, useState, useEffect, useCallback } from 'react';
import { VolumeLightingProps } from '../../types/ViewportPresets';
import { Numeric } from '@ohif/ui-next';
export function VolumeLighting({
servicesManager,
@@ -8,135 +9,75 @@ export function VolumeLighting({
hasShade,
}: VolumeLightingProps): ReactElement {
const { cornerstoneViewportService } = servicesManager.services;
const [ambient, setAmbient] = useState(null);
const [diffuse, setDiffuse] = useState(null);
const [specular, setSpecular] = useState(null);
const [lightingValues, setLightingValues] = useState({
ambient: null,
diffuse: null,
specular: null,
});
const onAmbientChange = useCallback(() => {
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { ambient } });
}, [ambient, commandsManager, viewportId]);
const onDiffuseChange = useCallback(() => {
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { diffuse } });
}, [diffuse, commandsManager, viewportId]);
const onSpecularChange = useCallback(() => {
commandsManager.runCommand('setVolumeLighting', { viewportId, options: { specular } });
}, [specular, commandsManager, viewportId]);
const calculateBackground = value => {
const percentage = ((value - 0) / (1 - 0)) * 100;
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
};
// Single callback to handle all lighting property changes
const onLightingChange = useCallback(
(property, value) => {
commandsManager.runCommand('setVolumeLighting', {
viewportId,
options: { [property]: value },
});
setLightingValues(prev => ({
...prev,
[property]: value,
}));
},
[commandsManager, viewportId]
);
useEffect(() => {
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const { actor } = viewport.getActors()[0];
const ambient = actor.getProperty().getAmbient();
const diffuse = actor.getProperty().getDiffuse();
const specular = actor.getProperty().getSpecular();
setAmbient(ambient);
setDiffuse(diffuse);
setSpecular(specular);
}, [viewportId, cornerstoneViewportService]);
const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40';
const disableSlider = !hasShade;
return (
<>
<div
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
>
<label
className="block text-white"
htmlFor="ambient"
>
Ambient
</label>
{ambient !== null && (
<input
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
value={ambient}
onChange={e => {
setAmbient(e.target.value);
onAmbientChange();
}}
id="ambient"
disabled={disableSlider}
max={1}
min={0}
type="range"
step={0.1}
style={{
background: calculateBackground(ambient),
'--thumb-inner-color': '#5acce6',
'--thumb-outer-color': '#090c29',
}}
/>
)}
</div>
<div
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
>
<label
className="block text-white"
htmlFor="diffuse"
>
Diffuse
</label>
{diffuse !== null && (
<input
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
value={diffuse}
onChange={e => {
setDiffuse(e.target.value);
onDiffuseChange();
}}
disabled={disableSlider}
id="diffuse"
max={1}
min={0}
type="range"
step={0.1}
style={{
background: calculateBackground(diffuse),
'--thumb-inner-color': '#5acce6',
'--thumb-outer-color': '#090c29',
}}
/>
)}
</div>
const property = actor.getProperty();
<div
className={`all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px] ${disableOption}`}
>
<label
className="block text-white"
htmlFor="specular"
>
Specular
</label>
{specular !== null && (
<input
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
value={specular}
disabled={disableSlider}
onChange={e => {
setSpecular(e.target.value);
onSpecularChange();
}}
id="specular"
max={1}
min={0}
type="range"
step={0.1}
style={{
background: calculateBackground(specular),
'--thumb-inner-color': '#5acce6',
'--thumb-outer-color': '#090c29',
}}
/>
)}
</div>
</>
const values = {
ambient: property.getAmbient(),
diffuse: property.getDiffuse(),
specular: property.getSpecular(),
};
setLightingValues(values);
}, [viewportId, cornerstoneViewportService]);
const disableOption = hasShade ? '' : 'ohif-disabled !opacity-40';
// Configuration for our lighting properties
const lightingProperties = [
{ key: 'ambient', label: 'Ambient' },
{ key: 'diffuse', label: 'Diffuse' },
{ key: 'specular', label: 'Specular' },
];
return (
<div className="my-1 mt-2 flex flex-col space-y-2">
{lightingProperties.map(
({ key, label }) =>
lightingValues[key] !== null && (
<div
key={key}
className={`w-full pl-2 pr-1 ${disableOption}`}
>
<Numeric.Container
mode="singleRange"
min={0}
max={1}
step={0.1}
value={lightingValues[key]}
onChange={value => onLightingChange(key, value)}
>
<div className="flex flex-row items-center">
<Numeric.Label className="w-16">{label}</Numeric.Label>
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
</div>
</Numeric.Container>
</div>
)
)}
</div>
);
}
@@ -1,5 +1,5 @@
import React, { ReactElement, useState } from 'react';
import { AllInOneMenu } from '@ohif/ui';
import { AllInOneMenu } from '@ohif/ui-next';
import { VolumeRenderingOptionsProps } from '../../types/ViewportPresets';
import { VolumeRenderingQuality } from './VolumeRenderingQuality';
import { VolumeShift } from './VolumeShift';
@@ -26,11 +26,11 @@ export function VolumeRenderingOptions({
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
<div className="all-in-one-menu-item mt-2 flex !h-[20px] w-full justify-start">
<div className="text-aqua-pale text-[13px]">LIGHTING</div>
<div className="mt-2 flex h-8 !h-[20px] w-full flex-shrink-0 items-center justify-start px-2 text-base">
<div className="text-muted-foreground text-sm">Lighting</div>
</div>
<div className="bg-primary-dark mt-1 mb-1 h-[2px] w-full"></div>
<div className="all-in-one-menu-item flex w-full justify-center">
<div className="bg-background mt-1 mb-1 h-px w-full"></div>
<div className="hover:bg-accent flex h-8 w-full flex-shrink-0 items-center px-2 text-base hover:rounded">
<VolumeShade
commandsManager={commandsManager}
servicesManager={servicesManager}
@@ -1,4 +1,4 @@
import { AllInOneMenu } from '@ohif/ui';
import { AllInOneMenu } from '@ohif/ui-next';
import { Icons } from '@ohif/ui-next';
import React, { ReactElement } from 'react';
import { VolumeRenderingPresetsProps } from '../../types/ViewportPresets';
@@ -1,5 +1,6 @@
import React, { ReactElement, useCallback, useState, useEffect } from 'react';
import { VolumeRenderingQualityProps } from '../../types/ViewportPresets';
import { Numeric } from '@ohif/ui-next';
export function VolumeRenderingQuality({
volumeRenderingQualityRange,
@@ -22,11 +23,6 @@ export function VolumeRenderingQuality({
[commandsManager, viewportId]
);
const calculateBackground = value => {
const percentage = ((value - 0) / (1 - 0)) * 100;
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
};
useEffect(() => {
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const { actor } = viewport.getActors()[0];
@@ -41,33 +37,26 @@ export function VolumeRenderingQuality({
setQuality(Math.sqrt(averageSpacing / (sampleDistance * 0.5)));
}
}, [cornerstoneViewportService, viewportId]);
return (
<>
<div className="all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]">
<label
className="block text-white"
htmlFor="volume"
>
Quality
</label>
{quality !== null && (
<input
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
value={quality}
id="volume"
max={max}
<div className="my-1 mt-2 flex flex-col space-y-2">
{quality !== null && (
<div className="w-full pl-2 pr-1">
<Numeric.Container
mode="singleRange"
min={min}
type="range"
max={max}
step={step}
onChange={e => onChange(parseInt(e.target.value, 10))}
style={{
background: calculateBackground((quality - min) / (max - min)),
'--thumb-inner-color': '#5acce6',
'--thumb-outer-color': '#090c29',
}}
/>
)}
</div>
</>
value={quality}
onChange={onChange}
>
<div className="flex flex-row items-center">
<Numeric.Label className="w-16">Quality</Numeric.Label>
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
</div>
</Numeric.Container>
</div>
)}
</div>
);
}
@@ -1,5 +1,5 @@
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
import { SwitchButton } from '@ohif/ui';
import { Switch } from '@ohif/ui-next';
import { VolumeShadeProps } from '../../types/ViewportPresets';
export function VolumeShade({
@@ -28,15 +28,18 @@ export function VolumeShade({
}, [viewportId, cornerstoneViewportService]);
return (
<SwitchButton
key={key}
label="Shade"
checked={shade}
onChange={() => {
setShade(!shade);
onClickShade(!shade);
onShadeChange(!shade);
}}
/>
<>
<span className="flex-grow">Shade</span>
<Switch
className="ml-2 flex-shrink-0"
key={key}
checked={shade}
onCheckedChange={() => {
setShade(!shade);
onClickShade(!shade);
onShadeChange(!shade);
}}
/>
</>
);
}
@@ -1,5 +1,6 @@
import React, { ReactElement, useCallback, useEffect, useState, useRef } from 'react';
import { VolumeShiftProps } from '../../types/ViewportPresets';
import { Numeric } from '@ohif/ui-next';
export function VolumeShift({
viewportId,
@@ -46,48 +47,32 @@ export function VolumeShift({
viewportId,
shift: shiftDifference,
});
setShift(newShift);
},
[commandsManager, viewportId, viewport]
);
const calculateBackground = value => {
const percentage = ((value - 0) / (1 - 0)) * 100;
return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
};
return (
<>
<div className="all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]">
<label
className="block text-white"
htmlFor="shift"
>
Shift
</label>
{step !== null && (
<input
className="bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg"
<div className="my-1 mt-2 flex flex-col space-y-2">
{step !== null && minShift !== null && maxShift !== null && (
<div className="w-full pl-2 pr-1">
<Numeric.Container
mode="singleRange"
min={minShift}
max={maxShift}
step={step}
value={shift}
onChange={e => {
const shiftValue = parseInt(e.target.value, 10);
setShift(shiftValue);
onChangeRange(shiftValue);
}}
id="shift"
onChange={onChangeRange}
onMouseDown={() => setIsBlocking(true)}
onMouseUp={() => setIsBlocking(false)}
max={maxShift}
min={minShift}
type="range"
step={step}
style={{
background: calculateBackground((shift - minShift) / (maxShift - minShift)),
'--thumb-inner-color': '#5acce6',
'--thumb-outer-color': '#090c29',
}}
/>
)}
</div>
</>
>
<div className="flex flex-row items-center">
<Numeric.Label className="w-16">Shift</Numeric.Label>
<Numeric.SingleRange sliderClassName="mx-2 flex-grow" />
</div>
</Numeric.Container>
</div>
)}
</div>
);
}
@@ -1,5 +1,5 @@
import React, { ReactElement, useCallback } from 'react';
import { AllInOneMenu } from '@ohif/ui';
import { AllInOneMenu } from '@ohif/ui-next';
import { WindowLevelPreset } from '../../types/WindowLevel';
import { CommandsManager } from '@ohif/core';
import { useTranslation } from 'react-i18next';
@@ -45,6 +45,7 @@ export function WindowLevel({
key={`${modality}-${index}`}
label={preset.description}
secondaryLabel={`${preset.window} / ${preset.level}`}
useIconSpace={false}
onClick={() => onSetWindowLevel(preset)}
/>
))}
@@ -1,7 +1,7 @@
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import { AllInOneMenu } from '@ohif/ui';
import { AllInOneMenu } from '@ohif/ui-next';
import { useViewportGrid } from '@ohif/ui-next';
import { Colormap } from './Colormap';
import { Colorbar } from './Colorbar';
@@ -119,8 +119,8 @@ export function WindowLevelActionMenu({
iconClassName={classNames(
// Visible on hover and for the active viewport
activeViewportId === viewportId ? 'visible' : 'invisible group-hover/pane:visible',
'flex shrink-0 cursor-pointer rounded active:text-white text-primary-light',
isLight ? ' hover:bg-secondary-dark' : 'hover:bg-secondary-light/60'
'flex shrink-0 cursor-pointer rounded active:text-foreground text-highlight',
isLight ? ' hover:bg-primary/30' : 'hover:bg-primary/30'
)}
menuStyle={{ maxHeight: vpHeight - 32, minWidth: 218 }}
onVisibilityChange={() => {
@@ -144,8 +144,10 @@ export function WindowLevelActionMenu({
key="colorLUTPresets"
itemLabel="Color LUT"
itemIcon="icon-color-lut"
className="flex h-[calc(100%-32px)] flex-col"
>
<Colormap
className="flex h-full w-full flex-col"
colormaps={colormaps}
viewportId={viewportId}
displaySets={displaySets.filter(ds => !nonWLModalities.includes(ds.Modality))}
@@ -0,0 +1,10 @@
export * from './AccordionGroup';
export * from './MeasurementTableNested';
export * from './StudyMeasurements';
export * from './MeasurementsMenu';
export * from './SeriesMeasurements';
export * from './StudyMeasurementsActions';
export * from './MeasurementsOrAdditionalFindings';
import DicomUpload from './DicomUpload/DicomUpload';
export { DicomUpload };
@@ -8,7 +8,7 @@ import React, {
} from 'react';
import PropTypes from 'prop-types';
import { Types, ViewportActionCornersLocations } from '@ohif/ui';
import { Types, ViewportActionCornersLocations } from '@ohif/ui-next';
import ViewportActionCornersService, {
ActionComponentInfo,
} from '../services/ViewportActionCornersService/ViewportActionCornersService';
@@ -0,0 +1,156 @@
import React from 'react';
import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
Icons,
useSegmentationTableContext,
useSegmentationExpanded,
} from '@ohif/ui-next';
import { useTranslation } from 'react-i18next';
import { useSystem } from '@ohif/core/src';
/**
* Custom dropdown menu component for segmentation panel that uses context for data
*/
export const CustomDropdownMenuContent = () => {
const { commandsManager } = useSystem();
const { t } = useTranslation('SegmentationTable');
const {
onSegmentationAdd,
onSegmentationRemoveFromViewport,
onSegmentationEdit,
onSegmentationDelete,
exportOptions,
activeSegmentation,
activeSegmentationId,
} = useSegmentationTableContext('CustomDropdownMenu');
// Try to get segmentation data from expanded context first, fall back to table context
let segmentation;
let segmentationId;
let allowExport = false;
try {
// Try to get from expanded context
const context = useSegmentationExpanded();
segmentation = context.segmentation;
segmentationId = segmentation.segmentationId;
} catch (e) {
// If not in expanded context, fallback to active segmentation from table context
segmentation = activeSegmentation;
segmentationId = activeSegmentationId;
}
// Determine if export is allowed for this segmentation
if (exportOptions && segmentationId) {
const exportOption = exportOptions.find(opt => opt.segmentationId === segmentationId);
allowExport = exportOption?.isExportable || false;
}
if (!segmentation || !segmentationId) {
return null;
}
const actions = {
storeSegmentation: async segmentationId => {
commandsManager.run({
commandName: 'storeSegmentation',
commandOptions: { segmentationId },
context: 'CORNERSTONE',
});
},
onSegmentationDownloadRTSS: segmentationId => {
commandsManager.run('downloadRTSS', { segmentationId });
},
onSegmentationDownload: segmentationId => {
commandsManager.run('downloadSegmentation', { segmentationId });
},
downloadCSVSegmentationReport: segmentationId => {
commandsManager.run('downloadCSVSegmentationReport', { segmentationId });
},
};
return (
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => onSegmentationAdd(segmentationId)}>
<Icons.Add className="text-foreground" />
<span className="pl-2">{t('Create New Segmentation')}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>{t('Manage Current Segmentation')}</DropdownMenuLabel>
<DropdownMenuItem onClick={() => onSegmentationRemoveFromViewport(segmentationId)}>
<Icons.Series className="text-foreground" />
<span className="pl-2">{t('Remove from Viewport')}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onSegmentationEdit(segmentationId)}>
<Icons.Rename className="text-foreground" />
<span className="pl-2">{t('Rename')}</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger className="pl-1">
<Icons.Export className="text-foreground" />
<span className="pl-2">{t('Download & Export')}</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuLabel className="flex items-center pl-0">
<Icons.Download className="h-5 w-5" />
<span className="pl-1">{t('Download')}</span>
</DropdownMenuLabel>
<DropdownMenuItem
onClick={e => {
e.preventDefault();
actions.downloadCSVSegmentationReport(segmentationId);
}}
>
{t('CSV Report')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={e => {
e.preventDefault();
actions.onSegmentationDownload(segmentationId);
}}
disabled={!allowExport}
>
{t('DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={e => {
e.preventDefault();
actions.onSegmentationDownloadRTSS(segmentationId);
}}
disabled={!allowExport}
>
{t('DICOM RTSS')}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel className="flex items-center pl-0">
<Icons.Export className="h-5 w-5" />
<span className="pl-1 pt-1">{t('Export')}</span>
</DropdownMenuLabel>
<DropdownMenuItem
onClick={e => {
e.preventDefault();
actions.storeSegmentation(segmentationId);
}}
disabled={!allowExport}
>
{t('DICOM SEG')}
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => onSegmentationDelete(segmentationId)}>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">{t('Delete')}</span>
</DropdownMenuItem>
</DropdownMenuContent>
);
};
@@ -0,0 +1,138 @@
import * as cornerstoneTools from '@cornerstonejs/tools';
import React from 'react';
import { Separator, Button, Tooltip, TooltipTrigger, TooltipContent, Icons } from '@ohif/ui-next';
import { useTranslation } from 'react-i18next';
import { roundNumber } from '@ohif/core/src/utils';
import { useSystem } from '@ohif/core/src';
interface CustomSegmentStatisticsHeaderProps {
segmentationId: string;
segmentIndex: number;
}
/**
* Custom header component for segment statistics
*/
export const CustomSegmentStatisticsHeader = ({
segmentationId,
segmentIndex,
}: CustomSegmentStatisticsHeaderProps) => {
const { servicesManager, commandsManager } = useSystem();
const { segmentationService } = servicesManager.services;
const { t } = useTranslation('SegmentationTable');
const segmentation = segmentationService.getSegmentation(segmentationId);
const segment = segmentation.segments[segmentIndex];
const cachedStats = segment.cachedStats;
const namedStats = cachedStats.namedStats;
if (!namedStats) {
return null;
}
const bidirectional = namedStats.bidirectional;
if (!bidirectional) {
return (
<div className="-mt-2 space-y-2">
<div className="flex">
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className="text-primary flex items-center gap-2"
onClick={() => {
commandsManager.run('runSegmentBidirectional', {
segmentationId,
segmentIndex,
});
}}
>
<Icons.ToolBidirectionalSegment className="h-5 w-5" />
<span>{t('Compute Largest Bidirectional')}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">{t('Add bidirectional measurement')}</TooltipContent>
</Tooltip>
</div>
<Separator className="bg-input" />
</div>
);
}
const { value, unit } = bidirectional;
const maxMajor = value.maxMajor;
const maxMinor = value.maxMinor;
const max = Math.max(maxMajor, maxMinor);
const min = Math.min(maxMajor, maxMinor);
const isVisible = cornerstoneTools.annotation.visibility.isAnnotationVisible(
bidirectional.annotationUID
);
return (
<div className="-mt-2 space-y-2">
<div className="flex items-center justify-between">
<div className="text-foreground">
<div>
L: {roundNumber(max)} {unit}
</div>
<div>
W: {roundNumber(min)} {unit}
</div>
</div>
<div className="flex gap-2">
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="ghost"
className={`h-6 w-6 transition-opacity`}
onClick={e => {
e.stopPropagation();
cornerstoneTools.annotation.visibility.setAnnotationVisibility(
bidirectional.annotationUID,
!isVisible
);
segmentationService.addOrUpdateSegmentation({
segmentationId,
segmentIndex,
});
}}
>
{isVisible ? (
<Icons.Hide className="h-6 w-6" />
) : (
<Icons.Show className="h-6 w-6" />
)}
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">{t('Toggle visibility')}</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => {
if (bidirectional.annotationUID) {
commandsManager.run('jumpToMeasurement', {
uid: bidirectional.annotationUID,
});
}
}}
>
<Icons.JumpToSlice />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">{t('Jump to measurement')}</TooltipContent>
</Tooltip>
</div>
</div>
<Separator className="bg-input" />
</div>
);
};
@@ -1,4 +1,4 @@
import { CinePlayer } from '@ohif/ui';
import { CinePlayer } from '@ohif/ui-next';
import DicomUpload from '../components/DicomUpload/DicomUpload';
export default {
@@ -1,77 +1,12 @@
import React from 'react';
import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
Icons,
} from '@ohif/ui-next';
import { CustomDropdownMenuContent } from './CustomDropdownMenuContent';
import { CustomSegmentStatisticsHeader } from './CustomSegmentStatisticsHeader';
import React, { useState } from 'react';
import { Switch } from '@ohif/ui-next';
export default function getSegmentationPanelCustomization({ commandsManager, servicesManager }) {
return {
'panelSegmentation.customDropdownMenuContent': ({
activeSegmentation,
onSegmentationAdd,
onSegmentationRemoveFromViewport,
onSegmentationEdit,
onSegmentationDelete,
allowExport,
storeSegmentation,
onSegmentationDownload,
onSegmentationDownloadRTSS,
t,
}) => (
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => onSegmentationAdd(activeSegmentation.segmentationId)}>
<Icons.Add className="text-foreground" />
<span className="pl-2">{t('Create New Segmentation')}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>{t('Manage Current Segmentation')}</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => onSegmentationRemoveFromViewport(activeSegmentation.segmentationId)}
>
<Icons.Series className="text-foreground" />
<span className="pl-2">{t('Remove from Viewport')}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onSegmentationEdit(activeSegmentation.segmentationId)}>
<Icons.Rename className="text-foreground" />
<span className="pl-2">{t('Rename')}</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger
disabled={!allowExport}
className="pl-1"
>
<Icons.Export className="text-foreground" />
<span className="pl-2">{t('Export & Download')}</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={() => storeSegmentation(activeSegmentation.segmentationId)}
>
{t('Export DICOM SEG')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => onSegmentationDownload(activeSegmentation.segmentationId)}
>
{t('Download DICOM SEG')}
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => onSegmentationDelete(activeSegmentation.segmentationId)}>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">{t('Delete')}</span>
</DropdownMenuItem>
</DropdownMenuContent>
),
'panelSegmentation.customDropdownMenuContent': CustomDropdownMenuContent,
'panelSegmentation.customSegmentStatisticsHeader': CustomSegmentStatisticsHeader,
'panelSegmentation.disableEditing': false,
'panelSegmentation.showAddSegment': true,
'panelSegmentation.onSegmentationAdd': () => {
@@ -81,15 +16,70 @@ export default function getSegmentationPanelCustomization({ commandsManager, ser
},
'panelSegmentation.tableMode': 'collapsed',
'panelSegmentation.readableText': {
lesionStats: 'Lesion Statistics',
minValue: 'Minimum Value',
maxValue: 'Maximum Value',
meanValue: 'Mean Value',
volume: 'Volume (ml)',
suvPeak: 'SUV Peak',
suvMax: 'Maximum SUV',
suvMaxIJK: 'SUV Max IJK',
lesionGlyoclysisStats: 'Lesion Glycolysis',
// the values will appear in this order
min: 'Min Value',
minLPS: 'Min Coord',
max: 'Max Value',
maxLPS: 'Max Coord',
mean: 'Mean Value',
stdDev: 'Standard Deviation',
count: 'Voxel Count',
median: 'Median',
skewness: 'Skewness',
kurtosis: 'Kurtosis',
peakValue: 'Peak Value',
peakLPS: 'Peak Coord',
volume: 'Volume',
lesionGlycolysis: 'Lesion Glycolysis',
center: 'Center',
},
'segmentationToolbox.config': () => {
// Get initial states based on current configuration
const [previewEdits, setPreviewEdits] = useState(false);
const [toggleSegmentEnabled, setToggleSegmentEnabled] = useState(false);
const [useCenterAsSegmentIndex, setUseCenterAsSegmentIndex] = useState(false);
const handlePreviewEditsChange = checked => {
setPreviewEdits(checked);
commandsManager.run('toggleSegmentPreviewEdit', { toggle: checked });
};
const handleToggleSegmentEnabledChange = checked => {
setToggleSegmentEnabled(checked);
commandsManager.run('toggleSegmentSelect', { toggle: checked });
};
const handleUseCenterAsSegmentIndexChange = checked => {
setUseCenterAsSegmentIndex(checked);
commandsManager.run('toggleUseCenterSegmentIndex', { toggle: checked });
};
return (
<div className="bg-muted flex flex-col gap-4 border-b border-b-[2px] border-black px-2 py-3">
<div className="flex items-center gap-2">
<Switch
checked={previewEdits}
onCheckedChange={handlePreviewEditsChange}
/>
<span className="text-base text-white">Preview edits before creating</span>
</div>
<div className="flex items-center gap-2">
<Switch
checked={useCenterAsSegmentIndex}
onCheckedChange={handleUseCenterAsSegmentIndexChange}
/>
<span className="text-base text-white">Use center as segment index</span>
</div>
<div className="flex items-center gap-2">
<Switch
checked={toggleSegmentEnabled}
onCheckedChange={handleToggleSegmentEnabledChange}
/>
<span className="text-base text-white">Hover on segment border to activate</span>
</div>
</div>
);
},
};
}
+1 -14
View File
@@ -51,19 +51,6 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
);
};
const wrappedPanelMeasurement = ({ configuration }) => {
return (
<PanelMeasurement
commandsManager={commandsManager}
servicesManager={servicesManager}
extensionManager={extensionManager}
configuration={{
...configuration,
}}
/>
);
};
return [
{
name: 'activeViewportWindowLevel',
@@ -76,7 +63,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
iconName: 'tab-linear',
iconLabel: 'Measure',
label: 'Measurement',
component: wrappedPanelMeasurement,
component: PanelMeasurement,
},
{
name: 'panelSegmentation',
@@ -190,16 +190,16 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
},
},
{
name: 'evaluate.mpr',
name: 'evaluate.displaySetIsReconstructable',
evaluate: ({ viewportId, disabledText = 'Selected viewport is not reconstructable' }) => {
const { protocol } = hangingProtocolService.getActiveProtocol();
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
if (!displaySetUIDs?.length) {
if (!viewport) {
return;
}
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
const areReconstructable = displaySets.every(displaySet => {
@@ -210,11 +210,8 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
return getDisabledState(disabledText);
}
const isMpr = protocol?.id === 'mpr';
return {
disabled: false,
className: utils.getToggledClassName(isMpr),
};
},
},
+1 -1
View File
@@ -64,7 +64,7 @@ export const fourUp = {
customViewportProps: {
hideOverlays: true,
},
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
syncGroups: [HYDRATE_SEG_SYNC_GROUP],
},
displaySets: [
{
@@ -71,7 +71,7 @@ export const mprAnd3DVolumeViewport = {
customViewportProps: {
hideOverlays: true,
},
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
syncGroups: [HYDRATE_SEG_SYNC_GROUP],
},
displaySets: [
{
+1 -1
View File
@@ -47,7 +47,7 @@ export const only3D = {
orientation: 'coronal',
customViewportProps: {
hideOverlays: true,
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
syncGroups: [HYDRATE_SEG_SYNC_GROUP],
},
},
displaySets: [
+17 -7
View File
@@ -30,6 +30,8 @@ import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledEle
import { id } from './id';
import { measurementMappingUtils } from './utils/measurementServiceMappings';
import PlanarFreehandROI from './utils/measurementServiceMappings/PlanarFreehandROI';
import RectangleROI from './utils/measurementServiceMappings/RectangleROI';
import type { PublicViewportOptions } from './services/ViewportService/Viewport';
import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool';
import ViewportActionCornersService from './services/ViewportActionCornersService/ViewportActionCornersService';
@@ -51,11 +53,11 @@ import { useMeasurements } from './hooks/useMeasurements';
import getPanelModule from './getPanelModule';
import PanelSegmentation from './panels/PanelSegmentation';
import PanelMeasurement from './panels/PanelMeasurement';
import DicomUpload from './components/DicomUpload/DicomUpload';
import { useSegmentations } from './hooks/useSegmentations';
import { StudySummaryFromMetadata } from './components/StudySummaryFromMetadata';
import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm';
import utils from './utils';
export * from './components';
const { imageRetrieveMetadataProvider } = cornerstone.utilities;
@@ -80,6 +82,7 @@ const stackRetrieveOptions = {
},
};
const unsubscriptions = [];
/**
*
*/
@@ -140,6 +143,8 @@ const cornerstoneExtension: Types.Extensions.Extension = {
useToggleOneUpViewportGridStore.getState().clearToggleOneUpViewportGridStore();
useSegmentationPresentationStore.getState().clearSegmentationPresentationStore();
segmentationService.removeAllSegmentations();
unsubscriptions.forEach(unsubscribe => unsubscribe());
},
/**
@@ -147,7 +152,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
*
* @param configuration.csToolsConfig - Passed directly to `initCornerstoneTools`
*/
preRegistration: function (props: Types.Extensions.ExtensionParams): Promise<void> {
preRegistration: async function (props: Types.Extensions.ExtensionParams): Promise<void> {
const { servicesManager, serviceProvidersManager } = props;
servicesManager.registerService(CornerstoneViewportService.REGISTRATION);
servicesManager.registerService(ToolGroupService.REGISTRATION);
@@ -165,15 +170,18 @@ const cornerstoneExtension: Types.Extensions.Extension = {
const { syncGroupService } = servicesManager.services;
syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer);
return init.call(this, props);
const initResult = await init.call(this, props);
unsubscriptions.push(...initResult.unsubscriptions);
return {
...initResult,
};
},
getToolbarModule,
getHangingProtocolModule,
getViewportModule({ servicesManager, commandsManager }) {
const ExtendedOHIFCornerstoneViewport = props => {
// const onNewImageHandler = jumpData => {
// commandsManager.runCommand('jumpToImage', jumpData);
// };
const { toolbarService } = servicesManager.services;
return (
@@ -190,6 +198,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
{
name: 'cornerstone',
component: ExtendedOHIFCornerstoneViewport,
isReferenceViewable: props => utils.isReferenceViewable({ ...props, servicesManager }),
},
];
},
@@ -234,6 +243,8 @@ const cornerstoneExtension: Types.Extensions.Extension = {
export type { PublicViewportOptions };
export {
measurementMappingUtils,
PlanarFreehandROI,
RectangleROI,
CornerstoneExtensionTypes as Types,
toolNames,
getActiveViewportEnabledElement,
@@ -254,7 +265,6 @@ export {
useSegmentations,
PanelSegmentation,
PanelMeasurement,
DicomUpload,
StudySummaryFromMetadata,
CornerstoneViewportDownloadForm,
utils,
+41 -34
View File
@@ -39,6 +39,11 @@ import { useLutPresentationStore } from './stores/useLutPresentationStore';
import { usePositionPresentationStore } from './stores/usePositionPresentationStore';
import { useSegmentationPresentationStore } from './stores/useSegmentationPresentationStore';
import { imageRetrieveMetadataProvider } from '@cornerstonejs/core/utilities';
import {
setupSegmentationDataModifiedHandler,
setupSegmentationModifiedHandler,
} from './utils/segmentationHandlers';
import { initializeWebWorkerProgressHandler } from './utils/initWebWorkerProgressHandler';
const { registerColormap } = csUtilities.colormap;
@@ -90,6 +95,8 @@ export default async function init({
cornerstoneViewportService,
hangingProtocolService,
viewportGridService,
segmentationService,
measurementService,
} = servicesManager.services;
window.services = servicesManager.services;
@@ -150,8 +157,6 @@ export default async function init({
);
});
// ... existing code ...
// add metadata providers
metaData.addProvider(
csUtilities.calibratedPixelSpacingMetadataProvider.get.bind(
@@ -177,6 +182,29 @@ export default async function init({
initCineService(servicesManager);
initStudyPrefetcherService(servicesManager);
[
measurementService.EVENTS.JUMP_TO_MEASUREMENT_LAYOUT,
measurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT,
].forEach(event => {
measurementService.subscribe(event, evt => {
const { measurement } = evt;
const { uid: annotationUID } = measurement;
cornerstoneTools.annotation.selection.setAnnotationSelected(annotationUID, true);
});
});
// Setup segmentation event handlers
const { unsubscribe: unsubscribeSegmentationDataModifiedHandler } =
setupSegmentationDataModifiedHandler({
segmentationService,
customizationService,
commandsManager,
});
const { unsubscribe: unsubscribeSegmentationModifiedHandler } = setupSegmentationModifiedHandler({
segmentationService,
});
// When a custom image load is performed, update the relevant viewports
hangingProtocolService.subscribe(
hangingProtocolService.EVENTS.CUSTOM_IMAGE_LOAD_PERFORMED,
@@ -262,10 +290,16 @@ export default async function init({
eventTarget.addEventListenerDebounced(
EVENTS.ERROR_EVENT,
({ detail }) => {
// Create a stable ID for deduplication based on error type and message
const errorId = `cornerstone-error-${detail.type}-${detail.message.substring(0, 50)}`;
uiNotificationService.show({
title: detail.type,
message: detail.message,
type: 'error',
id: errorId,
allowDuplicates: false, // Prevent duplicate error notifications
deduplicationInterval: 30000, // 30 seconds deduplication window
});
},
100
@@ -273,40 +307,13 @@ export default async function init({
// Call this function when initializing
initializeWebWorkerProgressHandler(servicesManager.services.uiNotificationService);
}
function initializeWebWorkerProgressHandler(uiNotificationService) {
const activeToasts = new Map();
const unsubscriptions = [
unsubscribeSegmentationDataModifiedHandler,
unsubscribeSegmentationModifiedHandler,
];
eventTarget.addEventListener(EVENTS.WEB_WORKER_PROGRESS, ({ detail }) => {
const { progress, type, id } = detail;
const cacheKey = `${type}-${id}`;
if (progress === 0 && !activeToasts.has(cacheKey)) {
const progressPromise = new Promise((resolve, reject) => {
activeToasts.set(cacheKey, { resolve, reject });
});
uiNotificationService.show({
id: cacheKey,
title: `${type}`,
message: `${type}: ${progress}%`,
autoClose: false,
promise: progressPromise,
promiseMessages: {
loading: `Computing...`,
success: `Completed successfully`,
error: 'Web Worker failed',
},
});
} else {
if (progress === 100) {
const { resolve } = activeToasts.get(cacheKey);
resolve({ progress, type });
activeToasts.delete(cacheKey);
}
}
});
return { unsubscriptions };
}
/**
@@ -1,6 +1,7 @@
import {
PanTool,
WindowLevelTool,
SegmentBidirectionalTool,
StackScrollTool,
VolumeRotateTool,
ZoomTool,
@@ -36,7 +37,10 @@ import {
LivewireContourTool,
OrientationMarkerTool,
WindowLevelRegionTool,
SegmentSelectTool,
RegionSegmentPlusTool,
} from '@cornerstonejs/tools';
import { LabelmapSlicePropagationTool, MarkerLabelmapTool } from '@cornerstonejs/ai';
import * as polySeg from '@cornerstonejs/polymorphic-segmentation';
import CalibrationLineTool from './tools/CalibrationLineTool';
@@ -44,6 +48,8 @@ import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool';
export default function initCornerstoneTools(configuration = {}) {
CrosshairsTool.isAnnotation = false;
LabelmapSlicePropagationTool.isAnnotation = false;
MarkerLabelmapTool.isAnnotation = false;
ReferenceLinesTool.isAnnotation = false;
AdvancedMagnifyTool.isAnnotation = false;
PlanarFreehandContourSegmentationTool.isAnnotation = false;
@@ -52,8 +58,14 @@ export default function initCornerstoneTools(configuration = {}) {
addons: {
polySeg,
},
computeWorker: {
autoTerminateOnIdle: {
enabled: false,
},
},
});
addTool(PanTool);
addTool(SegmentBidirectionalTool);
addTool(WindowLevelTool);
addTool(StackScrollTool);
addTool(VolumeRotateTool);
@@ -89,7 +101,10 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(OrientationMarkerTool);
addTool(WindowLevelRegionTool);
addTool(PlanarFreehandContourSegmentationTool);
addTool(SegmentSelectTool);
addTool(LabelmapSlicePropagationTool);
addTool(MarkerLabelmapTool);
addTool(RegionSegmentPlusTool);
// Modify annotation tools to use dashed lines on SR
const annotationStyle = {
textBoxFontSize: '15px',
@@ -142,6 +157,11 @@ const toolNames = {
OrientationMarker: OrientationMarkerTool.toolName,
WindowLevelRegion: WindowLevelRegionTool.toolName,
PlanarFreehandContourSegmentation: PlanarFreehandContourSegmentationTool.toolName,
SegmentBidirectional: SegmentBidirectionalTool.toolName,
SegmentSelect: SegmentSelectTool.toolName,
LabelmapSlicePropagation: LabelmapSlicePropagationTool.toolName,
MarkerLabelmap: MarkerLabelmapTool.toolName,
RegionSegmentPlus: RegionSegmentPlusTool.toolName,
};
export { toolNames };
@@ -7,7 +7,11 @@ import { toolNames } from './initCornerstoneTools';
import { onCompletedCalibrationLine } from './tools/CalibrationLineTool';
import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
import getSOPInstanceAttributes from './utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
import { triggerAnnotationRenderForViewportIds } from '@cornerstonejs/tools/utilities';
import {
setAnnotationLabel,
triggerAnnotationRenderForViewportIds,
} from '@cornerstonejs/tools/utilities';
import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledElement';
const { CORNERSTONE_3D_TOOLS_SOURCE_NAME, CORNERSTONE_3D_TOOLS_SOURCE_VERSION } = CSExtensionEnums;
const { removeAnnotation } = annotation.state;
@@ -34,6 +38,7 @@ const initMeasurementService = (
LivewireContour,
Probe,
UltrasoundDirectional,
SegmentBidirectional,
} = measurementServiceMappingsFactory(
measurementService,
displaySetService,
@@ -172,6 +177,14 @@ const initMeasurementService = (
UltrasoundDirectional.toMeasurement
);
measurementService.addMapping(
csTools3DVer1MeasurementSource,
'SegmentBidirectional',
SegmentBidirectional.matchingCriteria,
SegmentBidirectional.toAnnotation,
SegmentBidirectional.toMeasurement
);
return csTools3DVer1MeasurementSource;
};
@@ -181,6 +194,7 @@ const connectToolsToMeasurementService = (servicesManager: AppTypes.ServicesMana
displaySetService,
cornerstoneViewportService,
customizationService,
viewportGridService,
} = servicesManager.services;
const csTools3DVer1MeasurementSource = initMeasurementService(
measurementService,
@@ -188,7 +202,11 @@ const connectToolsToMeasurementService = (servicesManager: AppTypes.ServicesMana
cornerstoneViewportService,
customizationService
);
connectMeasurementServiceToTools(measurementService, cornerstoneViewportService);
connectMeasurementServiceToTools(
measurementService,
cornerstoneViewportService,
viewportGridService
);
const { annotationToMeasurement, remove } = csTools3DVer1MeasurementSource;
//
@@ -314,7 +332,11 @@ const connectToolsToMeasurementService = (servicesManager: AppTypes.ServicesMana
return csTools3DVer1MeasurementSource;
};
const connectMeasurementServiceToTools = (measurementService, cornerstoneViewportService) => {
const connectMeasurementServiceToTools = (
measurementService,
cornerstoneViewportService,
viewportGridService
) => {
const { MEASUREMENT_REMOVED, MEASUREMENTS_CLEARED, MEASUREMENT_UPDATED, RAW_MEASUREMENT_ADDED } =
measurementService.EVENTS;
@@ -338,6 +360,10 @@ const connectMeasurementServiceToTools = (measurementService, cornerstoneViewpor
measurementService.subscribe(
MEASUREMENT_UPDATED,
({ source, measurement, notYetUpdatedAtSource }) => {
if (!source) {
return;
}
if (source.name !== CORNERSTONE_3D_TOOLS_SOURCE_NAME) {
return;
}
@@ -357,7 +383,8 @@ const connectMeasurementServiceToTools = (measurementService, cornerstoneViewpor
}
if (data.label !== label) {
data.label = label;
const element = getActiveViewportEnabledElement(viewportGridService)?.viewport.element;
setAnnotationLabel(sourceAnnotation, element, label);
}
if (metadata.toolName === 'ArrowAnnotate') {
@@ -1,107 +1,87 @@
import React, { useEffect, useRef } from 'react';
import { utils } from '@ohif/core';
import { MeasurementTable } from '@ohif/ui-next';
import debounce from 'lodash.debounce';
import React from 'react';
import { useSystem } from '@ohif/core';
import { useMeasurements } from '../hooks/useMeasurements';
import StudyMeasurements from '../components/StudyMeasurements';
/**
* The PanelMeasurement is a fairly simple wrapper that gets the filtered
* measurements and then passes it on to the children component, default to
* the StudyMeasurements sub-component if no children are specified.
* Some example customizations that could work:
*
*
* Creates a default study measurements panel with default children:
* ```
* <PanelMEasurement>
* <StudyMeasurements />
* </PanelMeasurement>
* ```
*
* A study measurements with body replacement
* ```
* <StudyMeasurements>
* <SeriesMeasurements />
* </StudyMeasurements>
* ```
*
* A study measurements replacing just the trigger, leaving the default body
* ```
* <StudyMeasurements>
* <AccordionGroup.Trigger>
* This is a new custom trigger
* </AccordionGroup.Trigger>
*</StudyMeasurements>
* ```
*
* A study measurements with the trigger and body replaced
* ```
* <StudyMeasurements>
* <AccordionGroup.Trigger>
* This is a new custom trigger
* </AccordionGroup.Trigger>
* <SeriesMeasurements />
* </StudyMeasurements>
* ```
*
* A study measurements with a custom header for the additional findings
* ```
* <StudyMeasurements>
* <MeasurementOrAdditionalFindings>
* <AccordionGroup.Trigger groupName="additionalFindings">
* <CustomAdditionalFindingsHeader />
* </AccordionGroup.Trigger>
* <AccordionGroup.Trigger groupName="measurements">
* <CustomMeasurementsHeader />
* </AccordionGroup.Trigger>
* </MeasurementOrAdditionalFindings>
* </StudyMeasurements>
*```
*/
export default function PanelMeasurement(props): React.ReactNode {
const { measurementFilter, emptyComponent: EmptyComponent, children } = props;
const { filterAdditionalFindings: filterAdditionalFinding, filterAny } = utils.MeasurementFilters;
export type withAppAndFilters = withAppTypes & {
measurementFilter: (item) => boolean;
};
export default function PanelMeasurement({
servicesManager,
commandsManager,
customHeader,
measurementFilter = filterAny,
}: withAppAndFilters): React.ReactNode {
const measurementsPanelRef = useRef(null);
const { measurementService } = servicesManager.services;
const displayMeasurements = useMeasurements(servicesManager, {
const system = useSystem();
const displayMeasurements = useMeasurements(system.servicesManager, {
measurementFilter,
});
useEffect(() => {
if (displayMeasurements.length > 0) {
debounce(() => {
measurementsPanelRef.current.scrollTop = measurementsPanelRef.current.scrollHeight;
}, 300)();
}
}, [displayMeasurements.length]);
if (!displayMeasurements.length) {
return EmptyComponent ? (
<EmptyComponent items={displayMeasurements} />
) : (
<span className="text-white">No Measurements</span>
);
}
const bindCommand = (name: string | string[], options?) => {
return (uid: string) => {
commandsManager.run(name, { ...options, uid });
};
};
const jumpToImage = bindCommand('jumpToMeasurement', { displayMeasurements });
const removeMeasurement = bindCommand('removeMeasurement');
const renameMeasurement = bindCommand(['jumpToMeasurement', 'renameMeasurement'], {
displayMeasurements,
});
const toggleLockMeasurement = bindCommand('toggleLockMeasurement');
const toggleVisibilityMeasurement = bindCommand('toggleVisibilityMeasurement');
const additionalFilter = filterAdditionalFinding(measurementService);
const measurements = displayMeasurements.filter(
item => !additionalFilter(item) && measurementFilter(item)
);
const additionalFindings = displayMeasurements.filter(
item => additionalFilter(item) && measurementFilter(item)
);
const onArgs = {
onClick: jumpToImage,
onDelete: removeMeasurement,
onToggleVisibility: toggleVisibilityMeasurement,
onToggleLocked: toggleLockMeasurement,
onRename: renameMeasurement,
};
return (
<>
<div
className="invisible-scrollbar overflow-y-auto overflow-x-hidden"
ref={measurementsPanelRef}
data-cy={'trackedMeasurements-panel'}
>
<MeasurementTable
key="tracked"
title="Measurements"
data={measurements}
{...onArgs}
// onColor={changeColorMeasurement}
>
<MeasurementTable.Header>
{customHeader && (
<>
{typeof customHeader === 'function'
? customHeader({
additionalFindings,
measurements,
})
: customHeader}
</>
)}
</MeasurementTable.Header>
<MeasurementTable.Body />
</MeasurementTable>
{additionalFindings.length > 0 && (
<MeasurementTable
key="additional"
data={additionalFindings}
title="Additional Findings"
{...onArgs}
>
<MeasurementTable.Body />
</MeasurementTable>
)}
</div>
</>
);
if (children) {
const cloned = React.Children.map(children, child =>
React.cloneElement(child, {
items: displayMeasurements,
filter: measurementFilter,
})
);
return cloned;
}
// Need to merge defaults on the content props to ensure they get passed to children
return <StudyMeasurements items={displayMeasurements} />;
}
@@ -2,12 +2,10 @@ import React from 'react';
import { SegmentationTable } from '@ohif/ui-next';
import { useActiveViewportSegmentationRepresentations } from '../hooks/useActiveViewportSegmentationRepresentations';
import { metaData } from '@cornerstonejs/core';
import { useSystem } from '@ohif/core/src';
export default function PanelSegmentation({
servicesManager,
commandsManager,
children,
}: withAppTypes) {
export default function PanelSegmentation({ children }: withAppTypes) {
const { commandsManager, servicesManager } = useSystem();
const { customizationService, displaySetService } = servicesManager.services;
const { segmentationsWithRepresentations, disabled } =
@@ -15,217 +13,191 @@ export default function PanelSegmentation({
servicesManager,
});
const handlers = {
onSegmentationClick: (segmentationId: string) => {
commandsManager.run('setActiveSegmentation', { segmentationId });
},
onSegmentAdd: segmentationId => {
commandsManager.run('addSegment', { segmentationId });
},
onSegmentClick: (segmentationId, segmentIndex) => {
commandsManager.run('setActiveSegmentAndCenter', { segmentationId, segmentIndex });
},
onSegmentEdit: (segmentationId, segmentIndex) => {
commandsManager.run('editSegmentLabel', { segmentationId, segmentIndex });
},
onSegmentationEdit: segmentationId => {
commandsManager.run('editSegmentationLabel', { segmentationId });
},
onSegmentColorClick: (segmentationId, segmentIndex) => {
commandsManager.run('editSegmentColor', { segmentationId, segmentIndex });
},
onSegmentDelete: (segmentationId, segmentIndex) => {
commandsManager.run('deleteSegment', { segmentationId, segmentIndex });
},
onToggleSegmentVisibility: (segmentationId, segmentIndex, type) => {
commandsManager.run('toggleSegmentVisibility', { segmentationId, segmentIndex, type });
},
onToggleSegmentLock: (segmentationId, segmentIndex) => {
commandsManager.run('toggleSegmentLock', { segmentationId, segmentIndex });
},
onToggleSegmentationRepresentationVisibility: (segmentationId, type) => {
commandsManager.run('toggleSegmentationVisibility', { segmentationId, type });
},
onSegmentationDownload: segmentationId => {
commandsManager.run('downloadSegmentation', { segmentationId });
},
storeSegmentation: async segmentationId => {
commandsManager.run({
commandName: 'storeSegmentation',
commandOptions: { segmentationId },
context: 'CORNERSTONE',
});
},
onSegmentationDownloadRTSS: segmentationId => {
commandsManager.run('downloadRTSS', { segmentationId });
},
setStyle: (segmentationId, type, key, value) => {
commandsManager.run('setSegmentationStyle', { segmentationId, type, key, value });
},
toggleRenderInactiveSegmentations: () => {
commandsManager.run('toggleRenderInactiveSegmentations');
},
onSegmentationRemoveFromViewport: segmentationId => {
commandsManager.run('removeSegmentationFromViewport', { segmentationId });
},
onSegmentationDelete: segmentationId => {
commandsManager.run('deleteSegmentation', { segmentationId });
},
setFillAlpha: ({ type }, value) => {
commandsManager.run('setFillAlpha', { type, value });
},
setOutlineWidth: ({ type }, value) => {
commandsManager.run('setOutlineWidth', { type, value });
},
setRenderFill: ({ type }, value) => {
commandsManager.run('setRenderFill', { type, value });
},
setRenderOutline: ({ type }, value) => {
commandsManager.run('setRenderOutline', { type, value });
},
setFillAlphaInactive: ({ type }, value) => {
commandsManager.run('setFillAlphaInactive', { type, value });
},
getRenderInactiveSegmentations: () => {
return commandsManager.run('getRenderInactiveSegmentations');
},
};
// Extract customization options
const segmentationTableMode = customizationService.getCustomization(
'panelSegmentation.tableMode'
);
// custom onSegmentationAdd if provided
) as unknown as string;
const onSegmentationAdd = customizationService.getCustomization(
'panelSegmentation.onSegmentationAdd'
);
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');
const CustomDropdownMenuContent = customizationService.getCustomization(
'panelSegmentation.customDropdownMenuContent'
);
const CustomSegmentStatisticsHeader = customizationService.getCustomization(
'panelSegmentation.customSegmentStatisticsHeader'
);
// Create handlers object for all command runs
const handlers = {
onSegmentationClick: (segmentationId: string) => {
commandsManager.run('setActiveSegmentation', { segmentationId });
},
onSegmentAdd: segmentationId => {
commandsManager.run('addSegment', { segmentationId });
},
onSegmentClick: (segmentationId, segmentIndex) => {
commandsManager.run('setActiveSegmentAndCenter', { segmentationId, segmentIndex });
},
onSegmentEdit: (segmentationId, segmentIndex) => {
commandsManager.run('editSegmentLabel', { segmentationId, segmentIndex });
},
onSegmentationEdit: segmentationId => {
commandsManager.run('editSegmentationLabel', { segmentationId });
},
onSegmentColorClick: (segmentationId, segmentIndex) => {
commandsManager.run('editSegmentColor', { segmentationId, segmentIndex });
},
onSegmentDelete: (segmentationId, segmentIndex) => {
commandsManager.run('deleteSegment', { segmentationId, segmentIndex });
},
onToggleSegmentVisibility: (segmentationId, segmentIndex, type) => {
commandsManager.run('toggleSegmentVisibility', { segmentationId, segmentIndex, type });
},
onToggleSegmentLock: (segmentationId, segmentIndex) => {
commandsManager.run('toggleSegmentLock', { segmentationId, segmentIndex });
},
onToggleSegmentationRepresentationVisibility: (segmentationId, type) => {
commandsManager.run('toggleSegmentationVisibility', { segmentationId, type });
},
onSegmentationDownload: segmentationId => {
commandsManager.run('downloadSegmentation', { segmentationId });
},
setStyle: (segmentationId, type, key, value) => {
commandsManager.run('setSegmentationStyle', { segmentationId, type, key, value });
},
toggleRenderInactiveSegmentations: () => {
commandsManager.run('toggleRenderInactiveSegmentations');
},
onSegmentationRemoveFromViewport: segmentationId => {
commandsManager.run('removeSegmentationFromViewport', { segmentationId });
},
onSegmentationDelete: segmentationId => {
commandsManager.run('deleteSegmentation', { segmentationId });
},
setFillAlpha: ({ type }, value) => {
commandsManager.run('setFillAlpha', { type, value });
},
setOutlineWidth: ({ type }, value) => {
commandsManager.run('setOutlineWidth', { type, value });
},
setRenderFill: ({ type }, value) => {
commandsManager.run('setRenderFill', { type, value });
},
setRenderOutline: ({ type }, value) => {
commandsManager.run('setRenderOutline', { type, value });
},
setFillAlphaInactive: ({ type }, value) => {
commandsManager.run('setFillAlphaInactive', { type, value });
},
getRenderInactiveSegmentations: () => {
return commandsManager.run('getRenderInactiveSegmentations');
},
};
// Generate export options
const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => {
const { representationData, segmentationId } = segmentation;
const { Labelmap } = representationData;
if (!Labelmap) {
return {
segmentationId,
isExportable: true,
};
return { segmentationId, isExportable: true };
}
const referencedImageIds = Labelmap.referencedImageIds;
const firstImageId = referencedImageIds[0];
const instance = metaData.get('instance', firstImageId);
if (!instance) {
return {
segmentationId,
isExportable: false,
};
return { segmentationId, isExportable: false };
}
const SOPInstanceUID = instance.SOPInstanceUID || instance.SopInstanceUID;
const SeriesInstanceUID = instance.SeriesInstanceUID;
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
SeriesInstanceUID
);
const isExportable = displaySet?.isReconstructable;
return {
segmentationId,
isExportable,
isExportable: displaySet?.isReconstructable,
};
});
return (
<>
<SegmentationTable
disabled={disabled}
data={segmentationsWithRepresentations}
mode={segmentationTableMode}
title="Segmentations"
exportOptions={exportOptions}
disableEditing={disableEditing}
onSegmentationAdd={onSegmentationAdd}
onSegmentationClick={handlers.onSegmentationClick}
onSegmentationDelete={handlers.onSegmentationDelete}
showAddSegment={showAddSegment}
onSegmentAdd={handlers.onSegmentAdd}
onSegmentClick={handlers.onSegmentClick}
onSegmentEdit={handlers.onSegmentEdit}
onSegmentationEdit={handlers.onSegmentationEdit}
onSegmentColorClick={handlers.onSegmentColorClick}
onSegmentDelete={handlers.onSegmentDelete}
onToggleSegmentVisibility={handlers.onToggleSegmentVisibility}
onToggleSegmentLock={handlers.onToggleSegmentLock}
onToggleSegmentationRepresentationVisibility={
handlers.onToggleSegmentationRepresentationVisibility
}
onSegmentationDownload={handlers.onSegmentationDownload}
storeSegmentation={handlers.storeSegmentation}
onSegmentationDownloadRTSS={handlers.onSegmentationDownloadRTSS}
setStyle={handlers.setStyle}
toggleRenderInactiveSegmentations={handlers.toggleRenderInactiveSegmentations}
onSegmentationRemoveFromViewport={handlers.onSegmentationRemoveFromViewport}
setFillAlpha={handlers.setFillAlpha}
setOutlineWidth={handlers.setOutlineWidth}
setRenderFill={handlers.setRenderFill}
setRenderOutline={handlers.setRenderOutline}
setFillAlphaInactive={handlers.setFillAlphaInactive}
renderInactiveSegmentations={handlers.getRenderInactiveSegmentations()}
>
{children}
<SegmentationTable.Config />
<SegmentationTable.AddSegmentationRow />
// Common props for SegmentationTable
const tableProps = {
disabled,
data: segmentationsWithRepresentations,
mode: segmentationTableMode,
title: 'Segmentations',
exportOptions,
disableEditing,
onSegmentationAdd,
showAddSegment,
renderInactiveSegmentations: handlers.getRenderInactiveSegmentations(),
...handlers,
};
{segmentationTableMode === 'collapsed' ? (
<SegmentationTable.Collapsed>
<SegmentationTable.SelectorHeader>
const renderSegments = () => {
return (
<SegmentationTable.Segments>
<SegmentationTable.SegmentStatistics.Header>
<CustomSegmentStatisticsHeader />
</SegmentationTable.SegmentStatistics.Header>
<SegmentationTable.SegmentStatistics.Body />
</SegmentationTable.Segments>
);
};
// Render content based on mode
const renderModeContent = () => {
if (tableProps.mode === 'collapsed') {
return (
<SegmentationTable.Collapsed>
<SegmentationTable.Collapsed.Header>
<SegmentationTable.Collapsed.DropdownMenu>
<CustomDropdownMenuContent />
</SegmentationTable.SelectorHeader>
</SegmentationTable.Collapsed.DropdownMenu>
<SegmentationTable.Collapsed.Selector />
<SegmentationTable.Collapsed.Info />
</SegmentationTable.Collapsed.Header>
<SegmentationTable.Collapsed.Content>
<SegmentationTable.AddSegmentRow />
<SegmentationTable.Segments />
</SegmentationTable.Collapsed>
) : (
<SegmentationTable.Expanded>
<SegmentationTable.Header>
{renderSegments()}
</SegmentationTable.Collapsed.Content>
</SegmentationTable.Collapsed>
);
}
return (
<>
<SegmentationTable.Expanded>
<SegmentationTable.Expanded.Header>
<SegmentationTable.Expanded.DropdownMenu>
<CustomDropdownMenuContent />
</SegmentationTable.Header>
{/* <SegmentationTable.AddSegmentRow /> */}
<SegmentationTable.Segments />
</SegmentationTable.Expanded>
)}
</SegmentationTable>
</>
</SegmentationTable.Expanded.DropdownMenu>
<SegmentationTable.Expanded.Label />
<SegmentationTable.Expanded.Info />
</SegmentationTable.Expanded.Header>
<SegmentationTable.Expanded.Content>
<SegmentationTable.AddSegmentRow />
{renderSegments()}
</SegmentationTable.Expanded.Content>
</SegmentationTable.Expanded>
</>
);
};
return (
<SegmentationTable {...tableProps}>
{children}
<SegmentationTable.Config />
<SegmentationTable.AddSegmentationRow />
{renderModeContent()}
</SegmentationTable>
);
}
@@ -92,6 +92,7 @@ class SegmentationService extends PubSubService {
};
private _segmentationIdToColorLUTIndexMap: Map<string, number>;
private _segmentationGroupStatsMap: Map<string, any>;
readonly servicesManager: AppTypes.ServicesManager;
highlightIntervalId = null;
readonly EVENTS = EVENTS;
@@ -102,6 +103,8 @@ class SegmentationService extends PubSubService {
this._segmentationIdToColorLUTIndexMap = new Map();
this.servicesManager = servicesManager;
this._segmentationGroupStatsMap = new Map();
}
public onModeEnter(): void {
@@ -261,15 +264,24 @@ class SegmentationService extends PubSubService {
{
segmentationId,
type,
config,
suppressEvents = false,
}: {
segmentationId: string;
type?: csToolsEnums.SegmentationRepresentations;
config?: {
blendMode?: csEnums.BlendModes;
};
suppressEvents?: boolean;
}
): Promise<void> {
const segmentation = this.getSegmentation(segmentationId);
const csViewport = this.getAndValidateViewport(viewportId);
if (!csViewport) {
return;
}
const colorLUTIndex = this._segmentationIdToColorLUTIndexMap.get(segmentationId);
const defaultRepresentationType = csToolsEnums.SegmentationRepresentations.Labelmap;
@@ -298,7 +310,8 @@ class SegmentationService extends PubSubService {
segmentationId,
representationTypeToUse,
colorLUTIndex,
isConverted
isConverted,
config
);
if (!suppressEvents) {
@@ -352,7 +365,7 @@ class SegmentationService extends PubSubService {
type: LABELMAP,
data: {
imageIds: segImageIds,
referencedVolumeId: this._getVolumeIdForDisplaySet(displaySet),
// referencedVolumeId: this._getVolumeIdForDisplaySet(displaySet),
referencedImageIds: referenceImageIds,
},
},
@@ -388,13 +401,13 @@ class SegmentationService extends PubSubService {
): Promise<string> {
const { type } = options;
let { segmentationId } = options;
const { labelmapBufferArray } = segDisplaySet;
const { labelMapImages } = segDisplaySet;
if (type !== LABELMAP) {
throw new Error('Only labelmap type is supported for SEG display sets right now');
}
if (!labelmapBufferArray) {
if (!labelMapImages || !labelMapImages.length) {
throw new Error('SEG reading failed');
}
@@ -411,16 +424,34 @@ class SegmentationService extends PubSubService {
}
const imageIds = images.map(image => image.imageId);
const derivedImages = labelMapImages?.flat();
const derivedImageIds = derivedImages.map(image => image.imageId);
const derivedSegmentationImages = await imageLoader.createAndCacheDerivedLabelmapImages(
imageIds as string[]
);
segDisplaySet.images = derivedSegmentationImages.map(image => ({
segDisplaySet.images = derivedImages.map(image => ({
...image,
...metaData.get('instance', image.referencedImageId),
}));
segDisplaySet.imageIds = derivedImageIds;
// We should parse the segmentation as separate slices to support overlapping segments.
// This parsing should occur in the CornerstoneJS library adapters.
// For now, we use the volume returned from the library and chop it here.
let firstSegmentedSliceImageId = null;
for (let i = 0; i < derivedImages.length; i++) {
const voxelManager = derivedImages[i].voxelManager as csTypes.IVoxelManager<number>;
const scalarData = voxelManager.getScalarData();
voxelManager.setScalarData(scalarData);
// Check if this slice has any non-zero voxels and we haven't found one yet
if (!firstSegmentedSliceImageId && scalarData.some(value => value !== 0)) {
firstSegmentedSliceImageId = derivedImages[i].referencedImageId;
}
}
// assign the first non zero voxel image id to the segDisplaySet
segDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
const segmentsInfo = segDisplaySet.segMetadata.data;
const segments: { [segmentIndex: string]: cstTypes.Segment } = {};
@@ -478,30 +509,6 @@ class SegmentationService extends PubSubService {
addColorLUT(colorLUT, colorLUTIndex);
this._segmentationIdToColorLUTIndexMap.set(segmentationId, colorLUTIndex);
// now we need to chop the volume array into chunks and set the scalar data for each derived segmentation image
const volumeScalarData = new Uint8Array(labelmapBufferArray[0]);
// We should parse the segmentation as separate slices to support overlapping segments.
// This parsing should occur in the CornerstoneJS library adapters.
// For now, we use the volume returned from the library and chop it here.
let firstSegmentedSliceImageId = null;
for (let i = 0; i < derivedSegmentationImages.length; i++) {
const voxelManager = derivedSegmentationImages[i]
.voxelManager as csTypes.IVoxelManager<number>;
const scalarData = voxelManager.getScalarData();
const sliceData = volumeScalarData.slice(i * scalarData.length, (i + 1) * scalarData.length);
scalarData.set(sliceData);
voxelManager.setScalarData(scalarData);
// Check if this slice has any non-zero voxels and we haven't found one yet
if (!firstSegmentedSliceImageId && sliceData.some(value => value !== 0)) {
firstSegmentedSliceImageId = derivedSegmentationImages[i].referencedImageId;
}
}
// assign the first non zero voxel image id to the segDisplaySet
segDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
this._broadcastEvent(EVENTS.SEGMENTATION_LOADING_COMPLETE, {
segmentationId,
segDisplaySet,
@@ -512,8 +519,8 @@ class SegmentationService extends PubSubService {
representation: {
type: LABELMAP,
data: {
imageIds: derivedSegmentationImages.map(image => image.imageId),
referencedVolumeId: this._getVolumeIdForDisplaySet(referencedDisplaySet),
imageIds: derivedImageIds,
// referencedVolumeId: this._getVolumeIdForDisplaySet(referencedDisplaySet),
referencedImageIds: imageIds as string[],
},
},
@@ -564,11 +571,12 @@ class SegmentationService extends PubSubService {
const referencedImageIdsWithGeometry = Array.from(structureSet.ReferencedSOPInstanceUIDsSet);
const referencedImageIds = referencedDisplaySet.instances.map(image => image.imageId);
const referencedImageIds = referencedDisplaySet.imageIds;
// find the first image id that contains a referenced SOP instance UID
const firstSegmentedSliceImageId = referencedImageIds.find(imageId =>
referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId))
);
const firstSegmentedSliceImageId =
referencedImageIds?.find(imageId =>
referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId))
) || null;
rtDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
// Map ROI contours to RT Struct Data
@@ -602,10 +610,16 @@ class SegmentationService extends PubSubService {
const segments: { [segmentIndex: string]: cstTypes.Segment } = {};
let segmentsCachedStats = {};
// Create colorLUT array for RT structures
const colorLUT = [[0, 0, 0, 0]]; // First entry is transparent for index 0
// Process each segment similarly to the SEG function
for (const rtStructData of allRTStructData) {
const { data, id, color, segmentIndex, geometryId } = rtStructData;
// Add the color to the colorLUT array
colorLUT.push(color);
try {
const geometry = await geometryLoader.createAndCacheGeometry(geometryId, {
geometryData: {
@@ -647,6 +661,11 @@ class SegmentationService extends PubSubService {
}
}
// Create and register the colorLUT
const colorLUTIndex = getNextColorLUTIndex();
addColorLUT(colorLUT, colorLUTIndex);
this._segmentationIdToColorLUTIndexMap.set(segmentationId, colorLUTIndex);
// Assign processed segments to segmentation config
segmentation.config.segments = segments;
@@ -1058,6 +1077,33 @@ class SegmentationService extends PubSubService {
public getRenderInactiveSegmentations(viewportId: string): boolean {
return cstSegmentation.config.style.getRenderInactiveSegmentations(viewportId);
}
/**
* Sets statistics for a group of segmentations
* @param segmentationIds - Array of segmentation IDs that form the group
* @param stats - Statistics object containing metrics for the segmentation group
*
* @remarks
* This method stores statistical data for a group of related segmentations.
* The stats are stored using a composite key created from the sorted and joined
*/
public setSegmentationGroupStats(segmentationIds: string[], stats: any) {
const groupId = this.getGroupId(segmentationIds);
this._segmentationGroupStatsMap.set(groupId, stats);
}
/**
* Gets statistics for a group of segmentations
* @param segmentationIds - Array of segmentation IDs that form the group
* @returns The stored statistics object for the segmentation group if found, undefined otherwise
*/
public getSegmentationGroupStats(segmentationIds: string[]) {
const groupId = this.getGroupId(segmentationIds);
return this._segmentationGroupStatsMap.get(groupId);
}
private getGroupId(segmentationIds: string[]) {
return segmentationIds.sort().join(',');
}
/**
* Toggles the visibility of a segmentation in the state, and broadcasts the event.
@@ -1133,8 +1179,8 @@ class SegmentationService extends PubSubService {
highlightFunctionType = 'ease-in-out' // todo: make animation functions configurable from outside
): void {
const center = this._getSegmentCenter(segmentationId, segmentIndex);
if (!center) {
console.warn('No center found for segmentation', segmentationId, segmentIndex);
return;
}
@@ -1210,7 +1256,8 @@ class SegmentationService extends PubSubService {
const csViewport =
this.servicesManager.services.cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!csViewport) {
throw new Error(`Viewport with id ${viewportId} not found.`);
console.warn(`Viewport with id ${viewportId} not found.`);
return null;
}
return csViewport;
}
@@ -1327,12 +1374,15 @@ class SegmentationService extends PubSubService {
segmentationId: string,
representationType: csToolsEnums.SegmentationRepresentations,
colorLUTIndex: number,
isConverted: boolean
isConverted: boolean,
config?: {
blendMode?: csEnums.BlendModes;
}
): Promise<void> {
const representation = {
type: representationType,
segmentationId,
config: { colorLUTOrIndex: colorLUTIndex },
config: { colorLUTOrIndex: colorLUTIndex, ...config },
};
const addRepresentation = () =>
@@ -1722,6 +1772,12 @@ class SegmentationService extends PubSubService {
const { center } = cachedStats;
if (!center) {
return {
world: cachedStats.namedStats.center.value,
};
}
return center;
}
@@ -1,4 +1,4 @@
import { Types, getEnabledElementByViewportId } from '@cornerstonejs/core';
import { Enums as CoreEnums, Types, getEnabledElementByViewportId } from '@cornerstonejs/core';
import {
SynchronizerManager,
Synchronizer,
@@ -7,7 +7,8 @@ import {
} from '@cornerstonejs/tools';
const { createSynchronizer } = SynchronizerManager;
const { SEGMENTATION_REPRESENTATION_ADDED } = Enums.Events;
const { SEGMENTATION_REPRESENTATION_MODIFIED } = Enums.Events;
const { BlendModes } = CoreEnums;
export default function createHydrateSegmentationSynchronizer(
synchronizerName: string,
@@ -15,15 +16,16 @@ export default function createHydrateSegmentationSynchronizer(
): Synchronizer {
const stackImageSynchronizer = createSynchronizer(
synchronizerName,
SEGMENTATION_REPRESENTATION_ADDED,
(synchronizerInstance, sourceViewport, targetViewport, sourceEvent) =>
segmentationRepresentationModifiedCallback(
SEGMENTATION_REPRESENTATION_MODIFIED,
(synchronizerInstance, sourceViewport, targetViewport, sourceEvent) => {
return segmentationRepresentationModifiedCallback(
synchronizerInstance,
sourceViewport,
targetViewport,
sourceEvent,
{ servicesManager, options }
),
);
},
{
eventSource: 'eventTarget',
}
@@ -41,8 +43,8 @@ const segmentationRepresentationModifiedCallback = async (
) => {
const event = sourceEvent as ToolsTypes.EventTypes.SegmentationRepresentationModifiedEventType;
const { segmentationId, viewportId } = event.detail;
const { segmentationService, hangingProtocolService } = servicesManager.services;
const { segmentationId } = event.detail;
const { segmentationService } = servicesManager.services;
const targetViewportId = targetViewport.viewportId;
@@ -51,7 +53,6 @@ const segmentationRepresentationModifiedCallback = async (
const targetFrameOfReferenceUID = viewport.getFrameOfReferenceUID();
if (!targetFrameOfReferenceUID) {
console.debug('No frame of reference UID found for the target viewport');
return;
}
@@ -75,5 +76,9 @@ const segmentationRepresentationModifiedCallback = async (
await segmentationService.addSegmentationRepresentation(targetViewportId, {
segmentationId,
type,
config: {
blendMode:
viewport.getBlendMode() === 1 ? BlendModes.LABELMAP_EDGE_PROJECTION_BLEND : undefined,
},
});
};
@@ -1,5 +1,5 @@
import { PubSubService } from '@ohif/core';
import { ViewportActionCornersLocations } from '@ohif/ui';
import { ViewportActionCornersLocations } from '@ohif/ui-next';
import { ReactNode } from 'react';
export type ActionComponentInfo = {
@@ -38,7 +38,7 @@ const EVENTS = {
VIEWPORT_VOLUMES_CHANGED: 'event::cornerstoneViewportService:viewportVolumesChanged',
};
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: true };
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: false };
/**
* Handles cornerstone viewport logic including enabling, disabling, and
@@ -742,6 +742,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
// If you call loadStudyMetadata and it's not in the DicomMetadataStore cache, it should fire
// a request through the data source?
// (This call may or may not create sub-requests for series metadata)
const { displaySetService } = this.servicesManager.services;
const volumeInputArray = [];
const displaySetOptionsArray = viewportInfo.getDisplaySetOptions();
const { hangingProtocolService } = this.servicesManager.services;
@@ -750,7 +751,13 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
const displaySetInstanceUIDs = [];
for (const [index, data] of viewportData.data.entries()) {
const { volume, imageIds, displaySetInstanceUID } = data;
const { imageIds, displaySetInstanceUID } = data;
let volume = data.volume;
if (!volume) {
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
volume = csToolsUtils.getOrCreateImageVolume(displaySet.images.map(image => image.imageId));
}
displaySetInstanceUIDs.push(displaySetInstanceUID);
@@ -846,23 +853,29 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
if (addOverlayFn) {
addOverlayFn();
}
viewport.render();
volumesProperties.forEach(({ properties, volumeId }) => {
viewport.setProperties(properties, volumeId);
setTimeout(() => {
// seems like a hack but we need the actor to be ready first before
// we set the properties
viewport.setProperties(properties, volumeId);
viewport.render();
}, 0);
});
this.setPresentations(viewport.id, presentations, viewportInfo);
const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
if (!presentations.positionPresentation) {
const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
if (imageIndex !== undefined) {
csUtils.jumpToSlice(viewport.element, {
imageIndex,
});
if (imageIndex !== undefined) {
csUtils.jumpToSlice(viewport.element, {
imageIndex,
});
}
}
viewport.render();
this._broadcastEvent(this.EVENTS.VIEWPORT_VOLUMES_CHANGED, {
viewportInfo,
});
@@ -1177,6 +1190,20 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
}
});
}
/**
* Gets the display sets for a given viewport
* @param viewportId - The ID of the viewport to get display sets for
* @returns Array of display sets for the viewport
*/
public getViewportDisplaySets(viewportId: string): OhifTypes.DisplaySet[] {
const { displaySetService } = this.servicesManager.services;
const displaySetInstanceUIDs = this.viewportsDisplaySets.get(viewportId) || [];
return displaySetInstanceUIDs
.map(uid => displaySetService.getDisplaySetByUID(uid))
.filter(Boolean);
}
}
export default CornerstoneViewportService;
Loaded 100 of 593 files, more files were not shown because too many files have changed in this diff. Show more