Compare commits

...
Author SHA1 Message Date
ohif-bot 7323e63608 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.9.4
 - @ohif/viewer@4.7.1
2020-12-03 17:20:07 +00:00
Igor OctavianoandDavide Punzo 0baf18dcb2 fix: reset VOI on mpr reset (#2115)
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2020-12-03 18:11:14 +01:00
ohif-bot cca3d6bff2 chore(release): publish [skip ci]
- @ohif/extension-dicom-rt@0.5.0
 - @ohif/viewer@4.7.0
2020-12-03 16:47:50 +00:00
Igor OctavianoandDavide Punzo f3cecf129b feat: Update approach to better handle rtdose instead of disabling panel
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2020-12-03 17:36:02 +01:00
ohif-bot fe03fc6f55 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.9.3
 - @ohif/viewer@4.6.3
2020-12-03 16:11:30 +00:00
Davide Punzo b59187c74d Re #2113: disable 2D MPR when datasets have multiple slices for the same ImagePositionPatient (#2160)
fix: disable 2D MPR when datasets are 4D
2020-12-03 17:08:38 +01:00
ohif-bot 5210c80369 chore(release): publish [skip ci]
- @ohif/extension-dicom-tag-browser@0.1.1
 - @ohif/extension-vtk@1.9.2
 - @ohif/core@2.11.1
 - @ohif/ui@1.7.1
 - @ohif/viewer@4.6.2
2020-12-03 15:19:00 +00:00
Igor OctavianoandDavide Punzo f57725ac8b fix: fallback to original dataset VR for XS
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2020-12-03 16:15:27 +01:00
ohif-bot 138e0fb3bf chore(release): publish [skip ci]
- @ohif/extension-dicom-tag-browser@0.1.0
 - @ohif/extension-vtk@1.9.1
 - @ohif/core@2.11.0
 - @ohif/ui@1.7.0
 - @ohif/viewer@4.6.1
2020-12-03 13:13:18 +00:00
be494a7376 feat: add show scroll option to modal
Co-authored-by: Erik Ziegler <erik.sweed@gmail.com>
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2020-12-03 14:09:45 +01:00
ohif-bot ab23feefbb chore(release): publish [skip ci]
- @ohif/extension-vtk@1.9.0
 - @ohif/ui@1.6.0
 - @ohif/viewer@4.6.0
2020-12-03 12:29:32 +00:00
Igor OctavianoandDavide Punzo 4c079044f6 feat: Add error boundary and retry logic for network failures during dynamic imports (#2145)
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2020-12-03 13:23:43 +01:00
ohif-bot 81fcfc7370 chore(release): publish [skip ci]
- @ohif/extension-dicom-tag-browser@0.0.5
2020-12-03 11:09:11 +00:00
Davide Punzo 6ec6446787 Merge pull request #2187 from OHIF/fix/tag-viewer-broken
Tag viewer broken for RTSTRUCT series
2020-12-03 11:59:58 +01:00
Davide Punzo 4b5a43641a Merge branch 'master' into fix/tag-viewer-broken 2020-12-03 11:39:23 +01:00
Erik Ziegler 2fb0b01fe2 ci: Fix release workflow issues with Gitbook-cli and missing executors (#2196) 2020-12-03 11:04:34 +01:00
ohif-bot 3632e5d495 chore(release): publish [skip ci]
- @ohif/viewer@4.5.29
2020-12-03 09:29:55 +00:00
Erik Ziegleranddannyrb dfe566e2aa ci: Use containerized PACS for running end-to-end tests #1122 (#1290)
* ci: Use containerized PACS for running end-to-end tests

* Try to fix cypress test results

Co-authored-by: dannyrb <danny.ri.brown@gmail.com>
2020-12-03 10:26:22 +01:00
Danny Brown 6c5ad9e98d change our definition of stale 2020-12-02 09:00:03 -05:00
ohif-bot aeb7d5edcc chore(release): publish [skip ci]
- @ohif/extension-vtk@1.8.0
 - @ohif/i18n@0.53.0
 - @ohif/viewer@4.5.28
2020-11-30 13:09:54 +00:00
qqalexqq d5b89748c9 feat(i18n): Added Russian language localization.
Fixes in translation, also a few new words added.

Changed 'Study List' translation (spelling changed).
2020-11-30 14:08:11 +01:00
Erik Ziegler b161016edb fix: Add syncTranslations script 2020-11-30 14:08:11 +01:00
Matthias Goetzke 2fff2d511f feat(i18n): Added de (German) translations
improved translations

Update StudyList.json

Fixed typo
2020-11-30 14:08:11 +01:00
ohif-bot cc92f91c1f chore(release): publish [skip ci]
- @ohif/viewer@4.5.27
2020-11-30 12:19:35 +00:00
matthiasg d2e777bafc fix: added MAX_CONCURRENCY limit as each webworker costs RAM, and machines with e.g 24 cores crash the process (#2161) 2020-11-30 13:17:27 +01:00
igoroctaviano c0c3ab307d Add only valid sequences 2020-11-26 13:00:54 -03:00
ohif-bot 5121913ee6 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.16
 - @ohif/viewer@4.5.26
2020-11-19 11:28:20 +00:00
Davide Punzo 6ef2b19925 Update vtk crosshairs logic (#2177) 2020-11-19 12:26:56 +01:00
ohif-bot f2450be255 chore(release): publish [skip ci]
- @ohif/viewer@4.5.25
2020-11-13 14:57:31 +00:00
DanielandDaniel Schiffl 04ca32a93e chore: OpenID Connect: Remove hard-coded loadUserInfo to make it configurable (#2167)
* removed hard-coded loadUserInfo

* undo styling

Co-authored-by: Daniel Schiffl <daniel.schiffl@stryker.com>
2020-11-13 15:55:43 +01:00
ohif-bot c92de6c647 chore(release): publish [skip ci]
- @ohif/viewer@4.5.24
2020-11-02 10:40:06 +00:00
Orlando Brea 5b302843d4 fix issue #2130 - With config.showStudyList : false -> Still showing hyperlink to StudyList on Not Found Component 2020-11-02 11:37:55 +01:00
ohif-bot 7eb8c4c641 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.15
 - @ohif/ui@1.5.7
 - @ohif/viewer@4.5.23
2020-11-02 10:35:07 +00:00
matthiasg 619f361510 fix: Reordered definitions in providers to prevent uninitialized var access (#2108) 2020-11-02 11:33:16 +01:00
ohif-bot 330eeaa216 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.14
 - @ohif/viewer@4.5.22
2020-10-20 12:49:10 +00:00
James Petts d627dee3b2 Update crosshairs UI and fix bug where you could scroll offscreen. (#2126)
* Update crosshairs UI and fix bug where you could scroll offscreen.

* Update tests for removed rotate tool.
2020-10-20 14:45:52 +02:00
ohif-bot d8714ea9c4 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.13
 - @ohif/viewer@4.5.21
2020-10-15 14:17:26 +00:00
James Petts 3c05920705 [IDC-2098] Update RVTKJSV (#2107)
* Update RVTKJSV

* Update react-vtkjs-viewport

* Fix WWWC tool with new rvtkjsv version
2020-10-15 16:15:28 +02:00
ohif-bot c6629bda75 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.12
 - @ohif/viewer@4.5.20
2020-10-13 16:25:26 +00:00
James Petts 588bcc9d17 Throw error if data too large in WebGL 1 enabled browser (#2106) 2020-10-13 18:23:14 +02:00
ohif-bot c31f8f9d65 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.11
 - @ohif/viewer@4.5.19
2020-10-13 13:06:12 +00:00
James Petts c0280e28ca Bring in rotatable crosshairs. (#2101)
* Bring in rotatable crosshairs.

* Pull in react-vtkjs-viewport 0.13.1 fix.
2020-10-13 15:00:01 +02:00
ohif-bot 7c3ac387ef chore(release): publish [skip ci]
- @ohif/extension-dicom-rt@0.4.9
 - @ohif/viewer@4.5.18
2020-10-12 08:26:15 +00:00
James Petts d6f79d9ddf [IDC-2063] Harden RTSTRUCT import (#2102)
* WIP

* Fix RTSTRUCT import with missing ContourImageSequence
2020-10-12 10:24:28 +02:00
ohif-bot 9448993cf0 chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.9.6
 - @ohif/extension-dicom-html@1.2.9
 - @ohif/extension-dicom-rt@0.4.8
 - @ohif/extension-dicom-segmentation@0.4.7
 - @ohif/extension-dicom-tag-browser@0.0.4
 - @ohif/extension-vtk@1.7.10
 - @ohif/core@2.10.7
 - @ohif/viewer@4.5.17
2020-10-07 10:54:55 +00:00
James Petts 1c556b4cc3 Update dcmjs version (#2094) 2020-10-07 12:53:30 +02:00
ohif-bot 94a9067fe3 chore(release): publish [skip ci]
- @ohif/extension-debugging@0.1.6
 - @ohif/extension-dicom-rt@0.4.7
 - @ohif/extension-vtk@1.7.9
 - @ohif/ui@1.5.6
 - @ohif/viewer@4.5.16
2020-10-06 09:51:18 +00:00
James Petts cfba4df70e IDC-2064 & IDC-2059 add more options to debug extension (#2069)
* Add more to debug extension.

* Update and comment out unit tests broke from v3.
2020-10-06 11:48:56 +02:00
ohif-bot 11c1d12872 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.7.8
 - @ohif/core@2.10.6
 - @ohif/viewer@4.5.15
2020-09-30 18:03:17 +00:00
Ștefan Silviu-AlexandruandStefan Silviu 91364db882 fix: use SeriesMetadata method instead of property in findMostRecentStructuredReport (#2038)
fixes #1714

Call getInstanceCount() instead of manually checking length (which does not work)

Co-authored-by: Stefan Silviu <silviu.stefan@ab4.systems>
2020-09-30 20:01:07 +02:00
Nicolas Byl bea31d5fec fix: Enable port changes for Docker image using the PORT variable (#2016) 2020-09-30 19:55:28 +02:00
ohif-bot 48ecbc261a chore(release): publish [skip ci]
- @ohif/viewer@4.5.14
2020-09-30 10:19:10 +00:00
Woonchan ChoandWoonchan Cho 8bc467fb07 [IDC-2052] PWA start url (#2070)
Change start_url in manifest.json from "./index.html" to "./"

Co-authored-by: Woonchan Cho <wcho24@wustl.edu>
2020-09-30 12:16:18 +02:00
159 changed files with 2524 additions and 803 deletions

No files matched your search

+45 -22
View File
@@ -13,11 +13,23 @@ version: 2.1
##
orbs:
codecov: codecov/codecov@1.0.5
cypress: cypress-io/cypress@1.13.0
cypress: cypress-io/cypress@1.26.0
executors:
# Custom executor to override Cypress config
deploy-to-prod-executor:
docker:
- image: 'cypress/browsers:node14.15.0-chrome86-ff82'
environment:
CYPRESS_BASE_URL: https://ohif-staging.netlify.com/
chrome-and-pacs:
docker:
# Primary container image where all steps run.
- image: 'cypress/browsers:node14.15.0-chrome86-ff82'
- image: 'ohif/viewer-testdata:0.1-test'
defaults: &defaults
docker:
- image: circleci/node:12.9.1
- image: circleci/node:14.15.0
environment:
TERM: xterm # Enable colors in term
QUICK_BUILD: true
@@ -170,7 +182,7 @@ jobs:
DEPLOY_TO_DEV:
docker:
- image: circleci/node:12.9.1
- image: circleci/node:14.15.0
environment:
TERM: xterm
NETLIFY_SITE_ID: 32708787-c9b0-4634-b50f-7ca41952da77
@@ -185,7 +197,7 @@ jobs:
DEPLOY_TO_STAGING:
docker:
- image: circleci/node:12.9.1
- image: circleci/node:14.15.0
environment:
TERM: xterm
NETLIFY_SITE_ID: c7502ae3-b150-493c-8422-05701e44a969
@@ -200,7 +212,7 @@ jobs:
DEPLOY_TO_PRODUCTION:
docker:
- image: circleci/node:12.9.1
- image: circleci/node:14.15.0
environment:
TERM: xterm
NETLIFY_SITE_ID: 79c4a5da-5c95-4dc9-84f7-45fd9dfe21b0
@@ -257,7 +269,12 @@ jobs:
paths: .
DOCS_PUBLISH:
<<: *defaults
docker:
# Gitbook fails due to graceful-fs updates above this node version :-(
- image: circleci/node:12.9.1
environment:
TERM: xterm # Enable colors in term
working_directory: ~/repo
steps:
- checkout
- run:
@@ -317,16 +334,19 @@ workflows:
# E2E: PWA
- cypress/run:
name: 'E2E: PWA'
executor: cypress/browsers-chrome76
executor: chrome-and-pacs
browser: chrome
pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest
- run: |
# Clear yarn cache; update to latest
rm -rf ~/.yarn
npm i -g yarn
yarn -v
yarn: true
record: false
store_artifacts: false
record: true
store_artifacts: true
working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build
start: yarn run test:e2e:serve
spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'
wait-on: 'http://localhost:3000'
@@ -337,21 +357,22 @@ workflows:
path: platform/viewer/cypress/screenshots
- store_artifacts:
path: platform/viewer/cypress/videos
- store_test_results:
path: platform/viewer/cypress/results
requires:
- UNIT_TESTS
# E2E: script-tag
- cypress/run:
name: 'E2E: Script Tag'
executor: cypress/browsers-chrome76
executor: chrome-and-pacs
browser: chrome
pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v' # Use yarn latest
yarn: true
record: false
store_artifacts: false
record: true
store_artifacts: true
working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build:package
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build:package
start: yarn run test:e2e:serve
spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'
wait-on: 'http://localhost:3000'
@@ -362,6 +383,8 @@ workflows:
path: platform/viewer/cypress/screenshots
- store_artifacts:
path: platform/viewer/cypress/videos
- store_test_results:
path: platform/viewer/cypress/results
requires:
- UNIT_TESTS
@@ -372,7 +395,7 @@ workflows:
# Update hub.docker.org
- cypress/run:
name: 'Generate Percy Snapshots'
executor: cypress/browsers-chrome76
executor: chrome-and-pacs
browser: chrome
pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
@@ -380,7 +403,7 @@ workflows:
yarn: true
store_artifacts: false
working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build
# start server --> verify running --> percy + chrome + cypress
command: yarn run test:e2e:dist
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
@@ -449,7 +472,7 @@ workflows:
# and record a Cypress dashboard test run
- cypress/run:
name: 'Generate Percy Snapshots'
executor: cypress/browsers-chrome76
executor: chrome-and-pacs
browser: chrome
pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
@@ -457,7 +480,7 @@ workflows:
yarn: true
store_artifacts: false
working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build
# start server --> verify running --> percy + chrome + cypress
command: yarn run test:e2e:dist
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
+6
View File
@@ -28,6 +28,12 @@ if [ -n "$CLIENT_ID" ] || [ -n "$HEALTHCARE_API_ENDPOINT" ]
cp /usr/share/nginx/html/google.js /usr/share/nginx/html/app-config.js
fi
if [ -n "${PORT}" ]
then
echo "Changing port to ${PORT}..."
sed -i -e "s/listen 80/listen ${PORT}/g" /etc/nginx/conf.d/default.conf
fi
echo "Starting Nginx to serve the OHIF Viewer..."
exec "$@"
+2 -2
View File
@@ -2,9 +2,9 @@
# https://github.com/apps/stale
#
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 21
daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
daysUntilClose: 9000
# Issues with these labels will never be considered stale
exemptLabels:
- 'Story :raised_hands:'
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.9.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.5...@ohif/extension-cornerstone@2.9.6) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.9.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.9.4...@ohif/extension-cornerstone@2.9.5) (2020-09-29)
**Note:** Version bump only for package @ohif/extension-cornerstone
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "2.9.5",
"version": "2.9.6",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -36,7 +36,7 @@
"cornerstone-math": "^0.1.8",
"cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.1.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.5...@ohif/extension-debugging@0.1.6) (2020-10-06)
**Note:** Version bump only for package @ohif/extension-debugging
## [0.1.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.4...@ohif/extension-debugging@0.1.5) (2020-09-17)
**Note:** Version bump only for package @ohif/extension-debugging
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-debugging",
"version": "0.1.5",
"version": "0.1.6",
"description": "OHIF extension for debugging.",
"author": "OHIF",
"license": "MIT",
@@ -7,3 +7,8 @@
display: flex;
flex-direction: column;
}
.debug-report-modal-buttons-container {
display: flex;
flex-direction: row;
}
+38 -10
View File
@@ -9,12 +9,21 @@ const DubugReportModal = ({
servers,
extensionManager,
mailTo,
debugModalMessage,
}) => {
const mailToFunction = () => {
const StudyInstanceUID = Object.keys(studies.studyData)[0];
const copyDebugDataToClipboard = () => {
const body = getEmailBody();
const subject = encodeURI(`Issue with Study: ${StudyInstanceUID}`);
const textArea = document.createElement('textarea');
textArea.value = body;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
};
const getEmailBody = () => {
let body = `Enter the description of your problem here: \n\n\n`;
body += `============= SESSION INFO =============\n\n`;
@@ -55,13 +64,11 @@ const DubugReportModal = ({
body += `URL\t ${window.location.href}\n\n`;
// Layout
const { numRows, numColumns, viewportSpecificData } = viewports;
body += '== Viewport Layout ==\n';
body += `Rows\t${numRows}\n`;
body += `Columns\t${numColumns}\n\n`;
body += '== Viewports ==\n';
Object.keys(viewportSpecificData).forEach(viewportIndex => {
@@ -75,6 +82,16 @@ const DubugReportModal = ({
body += `[${row},${column}]\t${vsd.SeriesInstanceUID}\n`;
});
return body;
};
const mailToFunction = () => {
const StudyInstanceUID = Object.keys(studies.studyData)[0];
const subject = encodeURI(`Issue with Study: ${StudyInstanceUID}`);
let body = getEmailBody();
// TODO Text dump of rest of stuff.
body = encodeURI(body);
@@ -84,16 +101,27 @@ const DubugReportModal = ({
return (
<div className="debug-report-modal-container">
{mailTo ? (
{debugModalMessage ? <p>{debugModalMessage}</p> : null}
<div className="debug-report-modal-buttons-container">
{mailTo ? (
<div>
<ToolbarButton
label={'Send Bug Report'}
onClick={mailToFunction}
icon={'envelope-square'}
isActive={false}
/>
</div>
) : null}
<div>
<ToolbarButton
label={'Send Bug Report'}
onClick={mailToFunction}
icon={'envelope-square'}
label={'Copy To Clipboard'}
onClick={copyDebugDataToClipboard}
icon={'clipboard'}
isActive={false}
/>
</div>
) : null}
</div>
<div>
<table>
{getAppVersion()}
@@ -102,6 +102,7 @@ export function getCommands(context, servicesManager, extensionManager) {
servers={servers}
extensionManager={extensionManager}
mailTo={state.mailTo}
debugModalMessage={state.debugModalMessage}
/>
);
};
+8 -2
View File
@@ -36,8 +36,14 @@ export default {
sharedContext.dicomWebClient = dicomWebClient;
}
if (configuration && configuration.mailTo) {
state.mailTo = configuration.mailTo;
if (configuration) {
if (configuration.mailTo) {
state.mailTo = configuration.mailTo;
}
if (configuration.debugModalMessage) {
state.debugModalMessage = configuration.debugModalMessage;
}
}
},
+1 -1
View File
@@ -1,3 +1,3 @@
const state = { mailTo: undefined };
const state = { mailTo: undefined, message: undefined };
export default state;
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.2.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.8...@ohif/extension-dicom-html@1.2.9) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-dicom-html
## [1.2.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.2.7...@ohif/extension-dicom-html@1.2.8) (2020-09-10)
**Note:** Version bump only for package @ohif/extension-dicom-html
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-html",
"version": "1.2.8",
"version": "1.2.9",
"description": "OHIF extension for rendering structured reports to HTML",
"author": "OHIF",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"peerDependencies": {
"@ohif/core": "^0.50.0",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
+35
View File
@@ -3,6 +3,41 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.5.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.9...@ohif/extension-dicom-rt@0.5.0) (2020-12-03)
### Features
* Update approach to better handle rtdose instead of disabling panel ([f3cecf1](https://github.com/OHIF/Viewers/commit/f3cecf129b16f8d24d239aa44fdff7f46e6ba683))
## [0.4.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.8...@ohif/extension-dicom-rt@0.4.9) (2020-10-12)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.4.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.7...@ohif/extension-dicom-rt@0.4.8) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.4.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.6...@ohif/extension-dicom-rt@0.4.7) (2020-10-06)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.4.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.4.5...@ohif/extension-dicom-rt@0.4.6) (2020-09-17)
**Note:** Version bump only for package @ohif/extension-dicom-rt
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-rt",
"version": "0.4.6",
"version": "0.5.0",
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
"author": "OHIF",
"license": "MIT",
@@ -31,7 +31,8 @@
"@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"gl-matrix": "^3.3.0",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import cornerstoneTools from 'cornerstone-tools';
import cornerstone from 'cornerstone-core';
@@ -31,19 +31,20 @@ const refreshViewport = () => {
*
* @param {Object} props
* @param {Array} props.studies
* @param {Array} props.viewports - viewportSpecificData
* @param {Array} props.getActiveViewport - get active viewport data
* @param {number} props.activeIndex - activeViewportIndex
* @param {number} props.isOpen - isOpen
* @returns component
*/
const RTPanel = ({
studies,
viewports,
activeIndex,
isOpen,
onContourItemClick,
activeContexts = [],
contexts = {},
activeViewport,
getActiveViewport
}) => {
const isVTK = () => activeContexts.includes(contexts.VTK);
const isCornerstone = () => activeContexts.includes(contexts.CORNERSTONE);
@@ -54,11 +55,11 @@ const RTPanel = ({
referencedDisplaysets: [],
sets: [],
selectedSet: null,
isLocked: false
};
const [state, setState] = useState(DEFAULT_STATE);
const [showSettings, setShowSettings] = useState(false);
const activeViewport = viewports[activeIndex];
/*
* TODO: Improve the way we notify parts of the app that depends on rts to be loaded.
@@ -81,27 +82,32 @@ const RTPanel = ({
document.addEventListener('extensiondicomrtrtloaded', updateStructureSets);
return () => {
document.removeEventListener(
'extensiondicomrtrtloaded',
updateStructureSets
);
document.removeEventListener('extensiondicomrtrtloaded', updateStructureSets);
};
}, []);
useEffect(() => {
const studyMetadata = studyMetadataManager.get(activeViewport.StudyInstanceUID);
const referencedDisplaysets = studyMetadata.getDerivedDatasets({
referencedSeriesInstanceUID: activeViewport.SeriesInstanceUID,
Modality: 'RTSTRUCT',
});
setState(state => ({ ...state, isLocked: !referencedDisplaysets.length }));
}, [activeViewport]);
const updateStructureSets = () => {
const viewport = getActiveViewport();
const module = cornerstoneTools.getModule('rtstruct');
const StructureSets = module.state.StructureSets;
if (StructureSets && StructureSets.length) {
const viewportSets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
activeViewport.SeriesInstanceUID
viewport.SeriesInstanceUID
);
const studyMetadata = studyMetadataManager.get(
activeViewport.StudyInstanceUID
);
const studyMetadata = studyMetadataManager.get(viewport.StudyInstanceUID);
const referencedDisplaysets = studyMetadata.getDerivedDatasets({
referencedSeriesInstanceUID: activeViewport.SeriesInstanceUID,
referencedSeriesInstanceUID: viewport.SeriesInstanceUID,
Modality: 'RTSTRUCT',
});
@@ -118,10 +124,6 @@ const RTPanel = ({
}
};
useEffect(() => {
updateStructureSets();
}, [studies, viewports, activeIndex]);
useEffect(() => {
setShowSettings(showSettings && !isOpen);
}, [isOpen]);
@@ -232,78 +234,80 @@ const RTPanel = ({
<div className="dcmrt-panel">
<div className="dcmrt-panel-header">
<h3>RT Structure Sets</h3>
<Icon
className="cog-icon"
name="cog"
width="25px"
height="25px"
onClick={() => setShowSettings(true)}
/>
{!state.isLocked && (
<Icon
className="cog-icon"
name="cog"
width="25px"
height="25px"
onClick={() => setShowSettings(true)}
/>
)}
</div>
{!state.referencedDisplaysets.length && (
<LoadingIndicator expand height="70px" width="70px" />
)}
{state.sets &&
state.referencedDisplaysets.map(displaySet => {
const { SeriesInstanceUID, metadata, isLoaded } = displaySet;
{!state.isLocked && !state.referencedDisplaysets.length && <LoadingIndicator expand height="70px" width="70px" />}
{state.sets && state.referencedDisplaysets.map(displaySet => {
const { SeriesInstanceUID, metadata, isLoaded } = displaySet;
const module = cornerstoneTools.getModule('rtstruct');
const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
viewports[activeIndex].SeriesInstanceUID
);
const module = cornerstoneTools.getModule('rtstruct');
const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
activeViewport.SeriesInstanceUID
);
const loadedSet = sets.find(
set => set.SeriesInstanceUID === SeriesInstanceUID
);
return (
<PanelSection
key={SeriesInstanceUID}
title={metadata.StructureSetLabel}
loading={!isLoaded || !loadedSet}
visible={isLoaded && loadedSet && loadedSet.visible}
hideVisibleButton={!isLoaded}
expanded={
isLoaded &&
loadedSet.SeriesInstanceUID ===
state.selectedSet.SeriesInstanceUID
const loadedSet = sets.find(
set => set.SeriesInstanceUID === SeriesInstanceUID
);
if (!loadedSet) return null;
return (
<PanelSection
key={SeriesInstanceUID}
title={metadata.StructureSetLabel}
loading={!isLoaded || !loadedSet}
visible={isLoaded && loadedSet && loadedSet.visible}
hideVisibleButton={!isLoaded}
expanded={
isLoaded &&
loadedSet.SeriesInstanceUID ===
state.selectedSet.SeriesInstanceUID
}
onVisibilityChange={newVisibility => {
const module = cornerstoneTools.getModule('rtstruct');
if (newVisibility) {
module.setters.showStructureSet(loadedSet.SeriesInstanceUID);
} else {
module.setters.hideStructureSet(loadedSet.SeriesInstanceUID);
}
onVisibilityChange={newVisibility => {
const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
activeViewport.SeriesInstanceUID
);
setState(state => ({ ...state, sets }));
refreshViewport();
}}
onExpandChange={async () => {
if (!isLoaded) {
await displaySet.load(activeViewport, studies);
const module = cornerstoneTools.getModule('rtstruct');
if (newVisibility) {
module.setters.showStructureSet(loadedSet.SeriesInstanceUID);
} else {
module.setters.hideStructureSet(loadedSet.SeriesInstanceUID);
}
const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
viewports[activeIndex].SeriesInstanceUID
activeViewport.SeriesInstanceUID
);
setState(state => ({ ...state, sets }));
refreshViewport();
}}
onExpandChange={async () => {
if (!isLoaded) {
await displaySet.load(viewports[activeIndex], studies);
const module = cornerstoneTools.getModule('rtstruct');
const sets = module.getters.structuresSetsWhichReferenceSeriesInstanceUid(
viewports[activeIndex].SeriesInstanceUID
);
const selectedSet = sets.find(
set => set.SeriesInstanceUID === SeriesInstanceUID
);
setState(state => ({ ...state, selectedSet, sets }));
}
}}
>
<ScrollableArea>
<TableList headless>
{isLoaded &&
loadedSet.ROIContours.map(c => toContourItem(c, loadedSet))}
</TableList>
</ScrollableArea>
</PanelSection>
);
})}
const selectedSet = sets.find(
set => set.SeriesInstanceUID === SeriesInstanceUID
);
setState(state => ({ ...state, selectedSet, sets }));
}
}}
>
<ScrollableArea>
<TableList headless>
{isLoaded &&
loadedSet.ROIContours.map(c => toContourItem(c, loadedSet))}
</TableList>
</ScrollableArea>
</PanelSection>
);
})}
</div>
);
};
+84 -1
View File
@@ -4,6 +4,7 @@ import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
import transformPointsToImagePlane from './utils/transformPointsToImagePlane';
import TOOL_NAMES from './utils/toolNames';
import { vec3 } from 'gl-matrix';
const dicomlab2RGB = dcmjs.data.Colors.dicomlab2RGB;
const globalImageIdSpecificToolStateManager =
@@ -86,7 +87,14 @@ export default async function loadRTStruct(
ContourGeometricType,
} = ContourSequenceArray[c];
const sopInstanceUID = ContourImageSequence.ReferencedSOPInstanceUID;
const sopInstanceUID = ContourImageSequence
? ContourImageSequence.ReferencedSOPInstanceUID
: _getClosestSOPInstanceUID(
ContourData,
ContourGeometricType,
NumberOfContourPoints,
imageIdSopInstanceUidPairs
);
const imageId = _getImageId(imageIdSopInstanceUidPairs, sopInstanceUID);
const imageIdSpecificToolData = _getOrCreateImageIdSpecificToolData(
toolState,
@@ -324,3 +332,78 @@ function _getImageIdSopInstanceUidPairsForDisplaySet(
function _toArray(objOrArray) {
return Array.isArray(objOrArray) ? objOrArray : [objOrArray];
}
function _getClosestSOPInstanceUID(
ContourData,
ContourGeometricType,
NumberOfContourPoints,
imageIdSopInstanceUidPairs
) {
const closest = {
distance: Infinity,
sopInstanceUID: null,
};
let point;
switch (ContourGeometricType) {
case 'POINT':
point = ContourData;
break;
case 'CLOSED_PLANAR':
case 'OPEN_PLANAR':
// These are defined as planar, so get the of the region to get the
// Best mapping to a plane even if its potentially off center.
point = [0, 0, 0];
for (let p = 0; p < NumberOfContourPoints * 3; p += 3) {
point[0] += ContourData[p];
point[1] += ContourData[p + 1];
point[2] += ContourData[p + 2];
}
point[0] /= NumberOfContourPoints;
point[1] /= NumberOfContourPoints;
point[2] /= NumberOfContourPoints;
}
imageIdSopInstanceUidPairs.forEach(pair => {
const { imageId } = pair;
const imagePlaneModule = cornerstone.metaData.get(
'imagePlaneModule',
imageId
);
const distance = distanceFromPointToPlane(point, imagePlaneModule);
if (distance < closest.distance) {
closest.distance = distance;
closest.sopInstanceUID = pair.sopInstanceUID;
}
});
return closest.sopInstanceUID;
}
/**
*
* @param {number[3]} P - The point
* @param {object} imagePlaneModule The cornerstone metadata object for the imagePlane
*/
function distanceFromPointToPlane(P, imagePlaneModule) {
const {
rowCosines,
columnCosines,
imagePositionPatient: Q,
} = imagePlaneModule;
let N = [];
vec3.cross(N, rowCosines, columnCosines);
const [A, B, C] = N;
const D = -A * Q[0] - B * Q[1] - C * Q[2];
return Math.abs(A * P[0] + B * P[1] + C * P[2] + D); // Denominator is sqrt(A**2 + B**2 + C**2) which is 1 as its a normal vector
}
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.4.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.6...@ohif/extension-dicom-segmentation@0.4.7) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
## [0.4.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.4.5...@ohif/extension-dicom-segmentation@0.4.6) (2020-09-17)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-segmentation",
"version": "0.4.6",
"version": "0.4.7",
"description": "OHIF extension for viewing segmentations in the 2D MPR view",
"author": "OHIF",
"license": "MIT",
@@ -31,7 +31,7 @@
"@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
+38
View File
@@ -3,6 +3,44 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.1.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.1.0...@ohif/extension-dicom-tag-browser@0.1.1) (2020-12-03)
### Bug Fixes
* fallback to original dataset VR for XS ([f57725a](https://github.com/OHIF/Viewers/commit/f57725ac8bfd59ea46ab334a1823882afadefba1))
# [0.1.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.0.5...@ohif/extension-dicom-tag-browser@0.1.0) (2020-12-03)
### Features
* add show scroll option to modal ([be494a7](https://github.com/OHIF/Viewers/commit/be494a7376d15777dbe598289c4ecdb9f48a6a48))
## [0.0.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.0.4...@ohif/extension-dicom-tag-browser@0.0.5) (2020-12-03)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.0.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.0.3...@ohif/extension-dicom-tag-browser@0.0.4) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.0.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.0.2...@ohif/extension-dicom-tag-browser@0.0.3) (2020-09-24)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-tag-browser",
"version": "0.0.3",
"version": "0.1.1",
"description": "OHIF extension for checking DICOM headers.",
"author": "OHIF",
"license": "MIT",
@@ -28,7 +28,7 @@
},
"peerDependencies": {
"@ohif/core": "^2.6.0",
"dcmjs": "0.16.0",
"dcmjs": "0.16.5",
"react": "^16.8.6"
},
"dependencies": {
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { classes } from '@ohif/core';
import { classes, cornerstone as OHIFCornerstone } from '@ohif/core';
import dcmjs from 'dcmjs';
import DicomBrowserSelect from './DicomBrowserSelect';
import moment from 'moment';
@@ -10,6 +10,8 @@ const { ImageSet } = classes;
const { DicomMetaDictionary } = dcmjs.data;
const { nameMap } = DicomMetaDictionary;
const { metadataProvider } = OHIFCornerstone;
const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
const [
activeDisplaySetInstanceUID,
@@ -17,6 +19,7 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
] = useState(displaySetInstanceUID);
const [activeInstance, setActiveInstance] = useState(0);
const [tags, setTags] = useState([]);
const [meta, setMeta] = useState('');
const [instanceList, setInstanceList] = useState([]);
const [displaySetList, setDisplaySetList] = useState([]);
const [isImageStack, setIsImageStack] = useState(false);
@@ -83,6 +86,7 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
}
setTags(getSortedTags(metadata));
setMeta(metadata);
setInstanceList(instanceList);
setDisplaySetList(newDisplaySetList);
setIsImageStack(isImageStack);
@@ -114,41 +118,43 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
options={displaySetList}
/>
{instanceSelectList}
<DicomTagTable tags={tags}></DicomTagTable>
<DicomTagTable tags={tags} meta={meta}></DicomTagTable>
</div>
);
};
function DicomTagTable({ tags }) {
const rows = getFormattedRowsFromTags(tags);
function DicomTagTable({ tags, meta }) {
const rows = getFormattedRowsFromTags(tags, meta);
return (
<div>
<table className="dicom-tag-browser-table">
<tr>
<th className="dicom-tag-browser-table-left">Tag</th>
<th className="dicom-tag-browser-table-left">Value Representation</th>
<th className="dicom-tag-browser-table-left">Keyword</th>
<th className="dicom-tag-browser-table-left">Value</th>
</tr>
{rows.map(row => {
const className = row.className ? row.className : null;
<tbody>
<tr>
<th className="dicom-tag-browser-table-left">Tag</th>
<th className="dicom-tag-browser-table-left">Value Representation</th>
<th className="dicom-tag-browser-table-left">Keyword</th>
<th className="dicom-tag-browser-table-left">Value</th>
</tr>
{rows.map((row, index) => {
const className = row.className ? row.className : null;
return (
<tr className={className}>
<td>{row[0]}</td>
<td className="dicom-tag-browser-table-center">{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
);
})}
return (
<tr className={className} key={`DICOMTagRow-${index}`}>
<td>{row[0]}</td>
<td className="dicom-tag-browser-table-center">{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
function getFormattedRowsFromTags(tags) {
function getFormattedRowsFromTags(tags, meta) {
const rows = [];
tags.forEach(tagInfo => {
@@ -175,6 +181,17 @@ function getFormattedRowsFromTags(tags) {
rows.push(...formatedRowsFromTags);
});
} else {
if (tagInfo.vr === 'xs') {
try {
const dataset = metadataProvider.getStudyDataset(meta.StudyInstanceUID);
const tag = dcmjs.data.Tag.fromPString(tagInfo.tag).toCleanString();
const originalTagInfo = dataset[tag];
tagInfo.vr = originalTagInfo.vr;
} catch (error) {
console.error(`Failed to parse value representation for tag '${tagInfo.keyword}'`);
}
}
rows.push([
`${tagInfo.tagIndent}${tagInfo.tag}`,
tagInfo.vr,
@@ -247,10 +264,11 @@ function getRows(metadata, depth = 0) {
sequenceAsArray.forEach(item => {
const sequenceRows = getRows(item, depth + 1);
// Sort the sequence group.
_sortTagList(sequenceRows);
sequence.values.push(sequenceRows);
if (sequenceRows.length) {
// Sort the sequence group.
_sortTagList(sequenceRows);
sequence.values.push(sequenceRows);
}
});
continue;
@@ -276,13 +294,12 @@ function getRows(metadata, depth = 0) {
} else if (value.Alphabetic) {
value = value.Alphabetic;
} else {
console.error('Unrecognised Value for element:');
console.error(value);
console.warn(`Unrecognised Value: ${value} for ${keyword}:`);
console.warn(value);
value = ' ';
}
} else {
console.error('Unrecognised Value for element:');
console.error(value);
console.warn(`Unrecognised Value: ${value} for ${keyword}:`);
value = ' ';
}
}
@@ -21,7 +21,7 @@ export default function getCommandsModule(servicesManager) {
const { UIModalService } = servicesManager.services;
const WrappedDicomTagBrowser = function() {
const WrappedDicomTagBrowser = function () {
return (
<DicomTagBrowser
displaySets={displaySets}
@@ -34,6 +34,7 @@ export default function getCommandsModule(servicesManager) {
content: WrappedDicomTagBrowser,
title: `DICOM Tag Browser`,
fullscreen: true,
showScrollbar: true
});
},
};
+129
View File
@@ -3,6 +3,135 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.9.3...@ohif/extension-vtk@1.9.4) (2020-12-03)
### Bug Fixes
* reset VOI on mpr reset ([#2115](https://github.com/OHIF/Viewers/issues/2115)) ([0baf18d](https://github.com/OHIF/Viewers/commit/0baf18dcb2985378016236b735329346a851e14f))
## [1.9.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.9.2...@ohif/extension-vtk@1.9.3) (2020-12-03)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.9.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.9.1...@ohif/extension-vtk@1.9.2) (2020-12-03)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.9.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.9.0...@ohif/extension-vtk@1.9.1) (2020-12-03)
**Note:** Version bump only for package @ohif/extension-vtk
# [1.9.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.8.0...@ohif/extension-vtk@1.9.0) (2020-12-03)
### Features
* Add error boundary and retry logic for network failures during dynamic imports ([#2145](https://github.com/OHIF/Viewers/issues/2145)) ([4c07904](https://github.com/OHIF/Viewers/commit/4c079044f6ae2381c6054d8d77414100152d1d19))
# [1.8.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.16...@ohif/extension-vtk@1.8.0) (2020-11-30)
### Features
* **i18n:** Added de (German) translations ([2fff2d5](https://github.com/OHIF/Viewers/commit/2fff2d511fa1d36bdd6476da4ffa5684bf55374f))
## [1.7.16](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.15...@ohif/extension-vtk@1.7.16) (2020-11-19)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.15](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.14...@ohif/extension-vtk@1.7.15) (2020-11-02)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.14](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.13...@ohif/extension-vtk@1.7.14) (2020-10-20)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.13](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.12...@ohif/extension-vtk@1.7.13) (2020-10-15)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.12](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.11...@ohif/extension-vtk@1.7.12) (2020-10-13)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.11](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.10...@ohif/extension-vtk@1.7.11) (2020-10-13)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.9...@ohif/extension-vtk@1.7.10) (2020-10-07)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.8...@ohif/extension-vtk@1.7.9) (2020-10-06)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.7...@ohif/extension-vtk@1.7.8) (2020-09-30)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.7.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.7.6...@ohif/extension-vtk@1.7.7) (2020-09-17)
**Note:** Version bump only for package @ohif/extension-vtk
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
"version": "1.7.7",
"version": "1.9.4",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@@ -35,7 +35,7 @@
"cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"dicom-parser": "^1.8.3",
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
@@ -50,11 +50,11 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"lodash.throttle": "^4.1.1",
"react-vtkjs-viewport": "^0.10.4"
"react-vtkjs-viewport": "^0.14.2"
},
"devDependencies": {
"@ohif/core": "^2.10.5",
"@ohif/ui": "^1.5.5",
"@ohif/core": "^2.11.1",
"@ohif/ui": "^1.7.1",
"cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0",
"dicom-parser": "^1.8.3",
-37
View File
@@ -1,37 +0,0 @@
/**
* We use this component to leverage "Code Splitting"
*
* Link: https://serverless-stack.com/chapters/code-splitting-in-create-react-app.html
*/
import React, { Component } from 'react';
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null,
};
}
async componentDidMount() {
// Add dynamically loaded component to state
const { default: component } = await importComponent();
this.setState({
component: component,
});
}
render() {
const C = this.state.component;
// Render the loaded component, or null
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
+101 -18
View File
@@ -1,9 +1,9 @@
import throttle from 'lodash.throttle';
import {
vtkInteractorStyleMPRCrosshairs,
vtkInteractorStyleMPRWindowLevel,
vtkInteractorStyleRotatableMPRCrosshairs,
vtkSVGRotatableCrosshairsWidget,
vtkInteractorStyleMPRRotate,
vtkSVGCrosshairsWidget,
} from 'react-vtkjs-viewport';
import { getImageData } from 'react-vtkjs-viewport';
import { vec3 } from 'gl-matrix';
@@ -11,13 +11,13 @@ import setMPRLayout from './utils/setMPRLayout.js';
import setViewportToVTK from './utils/setViewportToVTK.js';
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants.js';
import OHIFVTKViewport from './OHIFVTKViewport';
import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
const { BlendMode } = Constants;
const commandsModule = ({ commandsManager }) => {
const commandsModule = ({ commandsManager, UINotificationService }) => {
// TODO: Put this somewhere else
let apis = {};
let defaultVOI;
async function _getActiveViewportVTKApi(viewports) {
const {
@@ -119,6 +119,16 @@ const commandsModule = ({ commandsManager }) => {
getVtkApis: ({ index }) => {
return apis[index];
},
resetMPRView() {
// Reset orientation
apis.forEach(api => api.resetOrientation());
// Reset VOI
if (defaultVOI) setVOI(defaultVOI);
// Reset the crosshairs
apis[0].svgWidgets.rotatableCrosshairsWidget.resetCrosshairs(apis, 0);
},
axial: async ({ viewports }) => {
const api = await _getActiveViewportVTKApi(viewports);
@@ -165,7 +175,7 @@ const commandsModule = ({ commandsManager }) => {
segmentNumber,
frameIndex,
frame,
done = () => { }
done = () => { },
}) => {
let api = apis[viewports.activeViewportIndex];
@@ -180,10 +190,13 @@ const commandsModule = ({ commandsManager }) => {
displaySetInstanceUID,
SOPClassUID,
SOPInstanceUID,
frameIndex,
frameIndex
);
const imageDataObject = getImageData(stack.imageIds, displaySetInstanceUID);
const imageDataObject = getImageData(
stack.imageIds,
displaySetInstanceUID
);
let pixelIndex = 0;
let x = 0;
@@ -209,9 +222,12 @@ const commandsModule = ({ commandsManager }) => {
y /= count;
const position = [x, y, frameIndex];
const worldPos = _convertModelToWorldSpace(position, imageDataObject.vtkImageData);
const worldPos = _convertModelToWorldSpace(
position,
imageDataObject.vtkImageData
);
api.svgWidgets.crosshairsWidget.moveCrosshairs(worldPos, apis);
api.svgWidgets.rotatableCrosshairsWidget.moveCrosshairs(worldPos, apis);
done();
},
setSegmentationConfiguration: async ({
@@ -254,21 +270,38 @@ const commandsModule = ({ commandsManager }) => {
await Promise.all(promises);
},
enableRotateTool: () => {
apis.forEach(api => {
apis.forEach((api, apiIndex) => {
const istyle = vtkInteractorStyleMPRRotate.newInstance();
api.setInteractorStyle({ istyle });
api.setInteractorStyle({
istyle,
configuration: { apis, apiIndex, uid: api.uid },
});
});
},
enableCrosshairsTool: () => {
apis.forEach((api, apiIndex) => {
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
const istyle = vtkInteractorStyleRotatableMPRCrosshairs.newInstance();
api.setInteractorStyle({
istyle,
configuration: { apis, apiIndex },
configuration: {
apis,
apiIndex,
uid: api.uid,
},
});
});
const rotatableCrosshairsWidget =
apis[0].svgWidgets.rotatableCrosshairsWidget;
const referenceLines = rotatableCrosshairsWidget.getReferenceLines();
// Initilise crosshairs if not initialised.
if (!referenceLines) {
rotatableCrosshairsWidget.resetCrosshairs(apis, 0);
}
},
enableLevelTool: () => {
function updateVOI(apis, windowWidth, windowCenter) {
@@ -291,10 +324,14 @@ const commandsModule = ({ commandsManager }) => {
},
};
apis.forEach(api => {
apis.forEach((api, apiIndex) => {
const istyle = vtkInteractorStyleMPRWindowLevel.newInstance();
api.setInteractorStyle({ istyle, callbacks });
api.setInteractorStyle({
istyle,
callbacks,
configuration: { apis, apiIndex, uid: api.uid },
});
});
},
setSlabThickness: ({ slabThickness }) => {
@@ -353,6 +390,7 @@ const commandsModule = ({ commandsManager }) => {
// Get current VOI if cornerstone viewport.
const cornerstoneVOI = getVOIFromCornerstoneViewport();
defaultVOI = cornerstoneVOI;
const viewportProps = [
{
@@ -391,18 +429,59 @@ const commandsModule = ({ commandsManager }) => {
// Add widgets and set default interactorStyle of each viewport.
apis.forEach((api, apiIndex) => {
api.addSVGWidget(
vtkSVGCrosshairsWidget.newInstance(),
'crosshairsWidget'
vtkSVGRotatableCrosshairsWidget.newInstance(),
'rotatableCrosshairsWidget'
);
const uid = api.uid;
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
const istyle = vtkInteractorStyleRotatableMPRCrosshairs.newInstance();
api.setInteractorStyle({
istyle,
configuration: { apis, apiIndex, uid },
});
api.svgWidgets.rotatableCrosshairsWidget.setApiIndex(apiIndex);
api.svgWidgets.rotatableCrosshairsWidget.setApis(apis);
});
const firstApi = apis[0];
// Initialise crosshairs
apis[0].svgWidgets.rotatableCrosshairsWidget.resetCrosshairs(apis, 0);
// Check if we have full WebGL 2 support
const openGLRenderWindow = apis[0].genericRenderWindow.getOpenGLRenderWindow();
if (!openGLRenderWindow.getWebgl2()) {
// Throw a warning if we don't have WebGL 2 support,
// And the volume is too big to fit in a 2D texture
const openGLContext = openGLRenderWindow.getContext();
const maxTextureSizeInBytes = openGLContext.getParameter(
openGLContext.MAX_TEXTURE_SIZE
);
const maxBufferLengthFloat32 =
(maxTextureSizeInBytes * maxTextureSizeInBytes) / 4;
const dimensions = firstApi.volumes[0]
.getMapper()
.getInputData()
.getDimensions();
const volumeLength = dimensions[0] * dimensions[1] * dimensions[2];
if (volumeLength > maxBufferLengthFloat32) {
UINotificationService.show({
title: 'Browser does not support WebGL 2',
message:
'This volume is too large to fit in WebGL 1 textures and will display incorrectly. Please use a different browser to view this data',
type: 'error',
autoClose: false,
});
}
}
},
};
@@ -456,6 +535,10 @@ const commandsModule = ({ commandsManager }) => {
commandFn: actions.enableLevelTool,
options: {},
},
resetMPRView: {
commandFn: actions.resetMPRView,
options: {},
},
setBlendModeToComposite: {
commandFn: actions.setBlendModeToComposite,
options: { blendMode: BlendMode.COMPOSITE_BLEND },
+6 -4
View File
@@ -1,5 +1,6 @@
import React from 'react';
import asyncComponent from './asyncComponent.js';
import { asyncComponent, retryImport } from '@ohif/ui';
import commandsModule from './commandsModule.js';
import toolbarModule from './toolbarModule.js';
import withCommandsManager from './withCommandsManager.js';
@@ -8,7 +9,7 @@ import { version } from '../package.json';
// import loadLocales from './loadLocales';
const OHIFVTKViewport = asyncComponent(() =>
import(/* webpackChunkName: "OHIFVTKViewport" */ './OHIFVTKViewport.js')
retryImport(() => import(/* webpackChunkName: "OHIFVTKViewport" */ './OHIFVTKViewport.js'))
);
const vtkExtension = {
@@ -27,8 +28,9 @@ const vtkExtension = {
getToolbarModule() {
return toolbarModule;
},
getCommandsModule({ commandsManager }) {
return commandsModule({ commandsManager });
getCommandsModule({ commandsManager, servicesManager }) {
const { UINotificationService } = servicesManager.services;
return commandsModule({ commandsManager, UINotificationService });
},
};
@@ -0,0 +1,3 @@
{
"Rotate": "Drehen"
}
+7
View File
@@ -0,0 +1,7 @@
import Buttons from './Buttons.json';
export default {
de: {
Buttons,
},
};
+3 -1
View File
@@ -1,7 +1,9 @@
import en from './en';
import es from './es';
import de from './de';
export default {
...en,
...es
...es,
...de,
};
@@ -31,7 +31,57 @@ const _isDisplaySetReconstructable = (viewportSpecificData = {}, activeViewportI
if (!displaySet) {
return false;
};
}
// 2D MPR is not currently available for 4D datasets.
// Assuming that slices at different time have the same position, here we just check if
// there are multiple slices for the same ImagePositionPatient and disable MPR.
// A better heuristic would be checking 4D tags, e.g. the presence of multiple TemporalPositionIdentifier values.
// However, some studies (e.g. https://github.com/OHIF/Viewers/issues/2113) do not have such tags.
for (let ii = 0; ii < displaySet.numImageFrames; ++ii){
const imageIdControl = displaySet.images[ii].getImageId()
const instanceMetadataControl = cornerstone.metaData.get('instance', imageIdControl)
if (!instanceMetadataControl ||
instanceMetadataControl === undefined ||
!instanceMetadataControl.ImagePositionPatient ||
instanceMetadataControl.ImagePositionPatient === undefined ) {
// if ImagePositionPatient is missing, skip the 4D datasets check.
// do not return false, because it could be a 3D dataset.
continue;
}
let xImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[0];
let yImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[1];
let zImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[2];
for (let jj = ii + 1; jj < displaySet.numImageFrames; ++jj){
const imageId = displaySet.images[jj].getImageId()
const instanceMetadata = cornerstone.metaData.get('instance', imageId)
if (!instanceMetadata ||
instanceMetadata === undefined ||
!instanceMetadata.ImagePositionPatient ||
instanceMetadata.ImagePositionPatient === undefined) {
// if ImagePositionPatient is missing, skip the 4D datasets check.
// do not return false, because it could be a 3D dataset.
continue;
}
let xImagePositionPatient = instanceMetadata.ImagePositionPatient[0];
let yImagePositionPatient = instanceMetadata.ImagePositionPatient[1];
let zImagePositionPatient = instanceMetadata.ImagePositionPatient[2];
if (xImagePositionPatientControl === xImagePositionPatient &&
yImagePositionPatientControl === yImagePositionPatient &&
zImagePositionPatientControl === zImagePositionPatient){
return false;
}
}
}
return displaySet.isReconstructable;
};
+12 -1
View File
@@ -25,6 +25,16 @@ const definitions = [
commandName: 'enableLevelTool',
commandOptions: {},
},
{
id: 'Reset',
label: 'Reset',
icon: 'reset',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'resetMPRView',
commandOptions: {},
},
/*
{
id: 'Rotate',
label: 'Rotate',
@@ -34,6 +44,7 @@ const definitions = [
commandName: 'enableRotateTool',
commandOptions: {},
},
*/
/*
{
id: 'setBlendModeToComposite',
@@ -131,4 +142,4 @@ const definitions = [
export default {
definitions,
defaultContext: 'ACTIVE_VIEWPORT::VTK',
}
};
+1
View File
@@ -28,6 +28,7 @@
"test:unit": "jest --collectCoverage",
"test:unit:ci": "lerna run test:unit:ci --parallel --stream",
"test:e2e": "lerna run test:e2e --stream",
"test:e2e:script-tag": "lerna run test:e2e:script-tag --stream",
"test:e2e:ci": "lerna run test:e2e:ci --stream",
"test:e2e:dist": "lerna run test:e2e:dist --stream",
"test:e2e:serve": "lerna run test:e2e:serve --stream",
+41
View File
@@ -3,6 +3,47 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.11.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.11.0...@ohif/core@2.11.1) (2020-12-03)
### Bug Fixes
* fallback to original dataset VR for XS ([f57725a](https://github.com/OHIF/Viewers/commit/f57725ac8bfd59ea46ab334a1823882afadefba1))
# [2.11.0](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.7...@ohif/core@2.11.0) (2020-12-03)
### Features
* add show scroll option to modal ([be494a7](https://github.com/OHIF/Viewers/commit/be494a7376d15777dbe598289c4ecdb9f48a6a48))
## [2.10.7](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.6...@ohif/core@2.10.7) (2020-10-07)
**Note:** Version bump only for package @ohif/core
## [2.10.6](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.5...@ohif/core@2.10.6) (2020-09-30)
### Bug Fixes
* use SeriesMetadata method instead of property in findMostRecentStructuredReport ([#2038](https://github.com/OHIF/Viewers/issues/2038)) ([91364db](https://github.com/OHIF/Viewers/commit/91364db8820efc86665db258d0044c16fb3e2c87)), closes [#1714](https://github.com/OHIF/Viewers/issues/1714)
## [2.10.5](https://github.com/OHIF/Viewers/compare/@ohif/core@2.10.4...@ohif/core@2.10.5) (2020-09-10)
**Note:** Version bump only for package @ohif/core
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/core",
"version": "2.10.5",
"version": "2.11.1",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",
@@ -39,7 +39,7 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"ajv": "^6.10.0",
"dcmjs": "0.16.3",
"dcmjs": "0.16.5",
"dicomweb-client": "^0.6.0",
"immer": "6.0.2",
"isomorphic-base64": "^1.0.2",
@@ -13,7 +13,7 @@ const findMostRecentStructuredReport = studies => {
// Skip series that may not have instances yet
// This can happen if we have retrieved just the initial
// details about the series via QIDO-RS, but not the full metadata
if (!series.instances || !series.instances.length) {
if (!series || series.getInstanceCount() === 0) {
return;
}
@@ -20,6 +20,7 @@ class MetadataProvider {
writable: false,
value: new Map(),
});
this.datasets = {};
}
async addInstance(dicomJSONDatasetOrP10ArrayBuffer, options = {}) {
@@ -52,6 +53,7 @@ class MetadataProvider {
SOPInstanceUID,
} = naturalizedDataset;
this._getAndCacheStudyDataset(StudyInstanceUID, dicomJSONDataset);
const study = this._getAndCacheStudy(StudyInstanceUID);
const series = this._getAndCacheSeriesFromStudy(study, SeriesInstanceUID);
const instance = this._getAndCacheInstanceFromStudy(series, SOPInstanceUID);
@@ -71,6 +73,16 @@ class MetadataProvider {
this.imageIdToUIDs.set(imageId, uids);
}
_getAndCacheStudyDataset(StudyInstanceUID, dataset) {
if (!this.datasets[StudyInstanceUID]) {
this.datasets[StudyInstanceUID] = dataset;
}
}
getStudyDataset(StudyInstanceUID) {
return this.datasets[StudyInstanceUID];
}
_getAndCacheStudy(StudyInstanceUID) {
const studies = this.studies;
@@ -83,6 +95,7 @@ class MetadataProvider {
return study;
}
_getAndCacheSeriesFromStudy(study, SeriesInstanceUID) {
let series = study.series.get(SeriesInstanceUID);
@@ -9,6 +9,7 @@
* @property {boolean} [closeButton=true] Should the modal body render the close button.
* @property {string} [title=null] Should the modal render the title independently of the body content.
* @property {string} [customClassName=null] The custom class to style the modal.
* @property {boolean} [showScrollbar=null] Show or hide scrollbar.
*/
const name = 'UIModalService';
@@ -28,7 +29,7 @@ const serviceImplementation = {
/**
* Show a new UI modal;
*
* @param {ModalProps} props { content, contentProps, shouldCloseOnEsc, isOpen, onClose, closeButton, title, customClassName }
* @param {ModalProps} props { content, contentProps, shouldCloseOnEsc, isOpen, onClose, closeButton, title, customClassName, showScrollbar }
*/
function _show({
content = null,
@@ -40,6 +41,7 @@ function _show({
title = null,
fullscreen = false,
customClassName = null,
showScrollbar = false
}) {
return serviceImplementation._show({
content,
@@ -51,6 +53,7 @@ function _show({
title,
fullscreen,
customClassName,
showScrollbar
});
}
+12 -12
View File
@@ -21,12 +21,12 @@ describe('Queue', () => {
const mockedTimeout = jest.fn(timeout);
const timer = queue.bind(mockedTimeout);
const start = Date.now();
timer(120).then(now => {
timer(1200).then(now => {
const elapsed = now - start;
expect(elapsed >= 120 && elapsed < 240).toBe(true);
expect(elapsed >= 1200 && elapsed < 2400).toBe(true);
});
const end = await timer(120);
expect(end - start > 240).toBe(true);
const end = await timer(1200);
expect(end - start > 2400).toBe(true);
expect(mockedTimeout).toBeCalledTimes(2);
});
it('should prevent task execution when queue limit is reached', async () => {
@@ -34,15 +34,15 @@ describe('Queue', () => {
const mockedTimeout = jest.fn(timeout);
const timer = queue.bind(mockedTimeout);
const start = Date.now();
const promise = timer(120).then(time => time - start);
const promise = timer(1200).then(time => time - start);
try {
await timer(120);
await timer(1200);
} catch (e) {
expect(Date.now() - start < 120).toBe(true);
expect(Date.now() - start < 1200).toBe(true);
expect(e.message).toBe('Queue limit reached');
}
const elapsed = await promise;
expect(elapsed >= 120 && elapsed < 240).toBe(true);
expect(elapsed >= 1200 && elapsed < 2400).toBe(true);
expect(mockedTimeout).toBeCalledTimes(1);
});
it('should safely bind tasks to the queue', async () => {
@@ -51,16 +51,16 @@ describe('Queue', () => {
const mockedTimeout = jest.fn(timeout);
const timer = queue.bindSafe(mockedTimeout, mockedErrorHandler);
const start = Date.now();
const promise = timer(120).then(time => time - start);
await timer(120);
expect(Date.now() - start < 120).toBe(true);
const promise = timer(1200).then(time => time - start);
await timer(1200);
expect(Date.now() - start < 1200).toBe(true);
expect(mockedErrorHandler).toBeCalledTimes(1);
expect(mockedErrorHandler).nthCalledWith(
1,
expect.objectContaining({ message: 'Queue limit reached' })
);
const elapsed = await promise;
expect(elapsed >= 120 && elapsed < 240).toBe(true);
expect(elapsed >= 1200 && elapsed < 2400).toBe(true);
expect(mockedTimeout).toBeCalledTimes(1);
});
});
+17
View File
@@ -3,6 +3,23 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.53.0](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.52.8...@ohif/i18n@0.53.0) (2020-11-30)
### Bug Fixes
* Add syncTranslations script ([b161016](https://github.com/OHIF/Viewers/commit/b161016edb8808ff0d17ea637820837dca1ca3ce))
### Features
* **i18n:** Added de (German) translations ([2fff2d5](https://github.com/OHIF/Viewers/commit/2fff2d511fa1d36bdd6476da4ffa5684bf55374f))
* **i18n:** Added Russian language localization. ([d5b8974](https://github.com/OHIF/Viewers/commit/d5b89748c92c2cf5a88f54ae491adc31a1679705))
## [0.52.8](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.52.7...@ohif/i18n@0.52.8) (2020-04-07)
**Note:** Version bump only for package @ohif/i18n
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/i18n",
"version": "0.52.8",
"version": "0.53.0",
"description": "Internationalization library for The OHIF Viewer",
"author": "OHIF",
"license": "MIT",
@@ -1,3 +0,0 @@
{
"No hotkeys found": "Nenhuma tecla de atalho está configurada para este aplicativo. As teclas de atalho podem ser configuradas no arquivo app-config.js do aplicativo."
}
-7
View File
@@ -1,7 +0,0 @@
import UserPreferencesModal from './UserPreferencesModal.json';
export default {
'ar': {
UserPreferencesModal,
}
};
@@ -0,0 +1,14 @@
{
"Browser": "Browser",
"Build Number": "Build Number",
"Latest Master Commits": "Letzter Master Commit",
"More details": "Mehr Details",
"Name": "Name",
"OHIF Viewer - About": "OHIF Viewer",
"OS": "OS",
"Report an issue": "Problem melden",
"Repository URL": "Repository URL",
"Value": "Wert",
"Version Information": "Versionsinformation",
"Visit the forum": "Das Forum besuchen"
}
+43
View File
@@ -0,0 +1,43 @@
{
"Acquired": "Akquiriert",
"Angle": "Winkel",
"Axial": "Axial",
"Bidirectional": "Bidirektional",
"Brush": "Pinsel",
"CINE": "CINE",
"Cancel": "Abbruch",
"Circle": "Kreis",
"Clear": "Entfernen",
"Coronal": "Coronal",
"Crosshairs": "Kreuzlinien",
"Download": "Herunterladen",
"Ellipse": "Ellipse",
"Elliptical": "Elliptisch",
"Flip H": "Spiegeln H",
"Flip V": "Spiegeln V",
"Freehand": "Freihand",
"Invert": "Invertieren",
"Layout": "$t(Common:Layout)",
"Length": "Länge",
"Levels": "Levels",
"Magnify": "Vergrössern",
"Manual": "Manuell",
"Measurements": "Messungen",
"More": "$t(Common:More)",
"Next": "$t(Common:Next)",
"Pan": "Verschieben",
"Play": "$t(Common:Play)",
"Previous": "$t(Common:Previous)",
"Probe": "Messung",
"ROI Window": "ROI Fenster",
"Rectangle": "Rechteck",
"Reset": "$t(Common:Reset)",
"Reset to Defaults": "Standardwerte",
"Rotate Right": "Rechts drehen",
"Sagittal": "Sagittal",
"Save": "Speichern",
"Stack Scroll": "Stapel",
"Stop": "$t(Common:Stop)",
"Themes": "Themes",
"Zoom": "Zoom"
}
@@ -0,0 +1,8 @@
{
"Next image": "$t(Common:Next) $t(Common:Image)",
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
"Previous image": "$t(Common:Previous) $t(Common:Image)",
"Skip to first image": "Zum ersten $t(Common:Image)",
"Skip to last image": "Zum letzten $t(Common:Image)",
"fps": "fps"
}
+16
View File
@@ -0,0 +1,16 @@
{
"Close": "Schliessen",
"Image": "Bild",
"Layout": "Layout",
"Measurements": "Messungen",
"More": "Mehr",
"Next": "Nächstes",
"Play": "Abspielen",
"Previous": "Zurück",
"Reset": "Zurücksetzen",
"RowsPerPage": "Zeilen pro Seite",
"Series": "Serie",
"Show": "Zeigen",
"Stop": "Stopp",
"StudyDate": "Studien Datum"
}
@@ -0,0 +1,5 @@
{
"Clear dates": "Zeiträume löschen",
"End Date": "Bis",
"Start Date": "Ab"
}
+8
View File
@@ -0,0 +1,8 @@
{
"About": "Über",
"Back to Viewer": "Zurück zum Viewer",
"INVESTIGATIONAL USE ONLY": "NICHT ZUR BEFUNDUNG FREIGEGEBEN",
"Options": "Optionen",
"Preferences": "Einstellungen",
"Study list": "Studienliste"
}
@@ -0,0 +1,9 @@
{
"Criteria nonconformities": "Kriterien für Nichtkonformität",
"Delete": "Löschen",
"Description": "Beschreibung",
"MAX": "MAX",
"NonTargets": "NichtZiele",
"Relabel": "Umbenennen",
"Targets": "Ziele"
}
@@ -0,0 +1,10 @@
{
"AccessionNumber": "Accession #",
"Empty": "Leer",
"MRN": "MRN",
"Modality": "Modalität",
"PatientName": "Patientenname",
"StudyDate": "Studiendatum",
"StudyDescription": "Beschreibung",
"StudyList": "Studienliste"
}
@@ -0,0 +1,9 @@
{
"Cancel": "$t(Buttons:Cancel)",
"No hotkeys found": "Keine Tastaturkürzel konfiguriert. Tastaturkürzel können in der app-config.js Datei der Anwendung konfiguriert werden.",
"Reset to Defaults": "$t(Buttons:Reset to Defaults)",
"ResetDefaultMessage": "Einstellungen erfolgreich zurückgesetzt. <br /> Sie müssen <strong>Speichern</strong> um dieses abzuschliessen.",
"Save": "$t(Buttons:Save)",
"SaveMessage": "Einstellungen gesichert",
"User Preferences": "Benutzereinstellungen"
}
@@ -0,0 +1,14 @@
{
"emptyFilenameError": "Dateiname kann nicht leer sein.",
"fileType": "Dateityp",
"filename": "Dateiname",
"formTitle": "Bitte geben Sie die Dimensionen, Dateiname und den gewünschten Dateityp an.",
"imageHeight": "Bildhöhe (px)",
"imagePreview": "Bild Vorschau",
"imageWidth": "Bildbreite (px)",
"keepAspectRatio": "Seitenverhältnis erbehalten",
"loadingPreview": "Bildvorschau laden...",
"minHeightError": "Die minimale Höhe beträgt 100 Pixel.",
"minWidthError": "Die minimale Breiete beträgt 100 Pixel.",
"showAnnotations": "Annotationen anzeigen"
}
+25
View File
@@ -0,0 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'de': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+6
View File
@@ -1,19 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'es': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+10
View File
@@ -1,15 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'fr': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
+4 -2
View File
@@ -1,21 +1,23 @@
import ar from './ar/';
import de from './de/';
import en_US from './en-US/';
import es from './es/';
import fr from './fr/';
import ja_JP from './ja-JP/';
import nl from './nl/';
import pt_BR from './pt-BR/';
import ru from './ru/';
import vi from './vi/';
import zh from './zh/';
export default {
...ar,
...de,
...en_US,
...es,
...fr,
...ja_JP,
...nl,
...pt_BR,
...ru,
...vi,
...zh,
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+10
View File
@@ -1,15 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'ja-JP': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+14
View File
@@ -1,11 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'nl': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+6
View File
@@ -4,7 +4,10 @@ import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'pt-BR': {
@@ -14,6 +17,9 @@ export default {
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1,14 @@
{
"Browser": "Браузер",
"Build Number": "Номер сборки",
"Latest Master Commits": "Последние коммиты в мастер",
"More details": "Больше подробностей",
"Name": "Имя",
"OHIF Viewer - About": "OHIF Viewer - помощь",
"OS": "ОС",
"Report an issue": "Сообщить о проблеме",
"Repository URL": "Ссылка репозитория",
"Value": "Значение",
"Version Information": "Информация о версии",
"Visit the forum": "Посетить форум"
}
+44
View File
@@ -0,0 +1,44 @@
{
"Acquired": "Полученные",
"Angle": "Угол",
"Annotate": "Примечание",
"Axial": "По оси",
"Bidirectional": "Двунаправленная",
"Brush": "Кисть",
"CINE": "Видео",
"Cancel": "Отменить",
"Circle": "Круг",
"Clear": "Очистить",
"Coronal": "Корональный",
"Crosshairs": "Перекрестие",
"Download": "Скачать",
"Ellipse": "Эллипс",
"Elliptical": "Эллиптический",
"Flip H": "Перевернуть ↔",
"Flip V": "Перевернуть ↕",
"Freehand": "От руки",
"Invert": "Инвертировать",
"Layout": "$t(Common:Layout)",
"Length": "Длина",
"Levels": "Уровни",
"Magnify": "Увеличить",
"Manual": "Ручной",
"Measurements": "Измерения",
"More": "$t(Common:More)",
"Next": "$t(Common:Next)",
"Pan": "Переместить",
"Play": "$t(Common:Play)",
"Previous": "$t(Common:Previous)",
"Probe": "Проба",
"ROI Window": "Главная область",
"Rectangle": "Прямоугольник",
"Reset": "$t(Common:Reset)",
"Reset to Defaults": "$t(Common:Reset) к настройкам по-умолчанию",
"Rotate Right": "Повернуть вправо",
"Sagittal": "Сагиттальный",
"Save": "Сохранить",
"Stack Scroll": "Прокрутка серии",
"Stop": "$t(Common:Stop)",
"Themes": "Темы",
"Zoom": "Лупа"
}
@@ -0,0 +1,8 @@
{
"Next image": "$t(Common:Next) $t(Common:Image)",
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
"Previous image": "$t(Common:Previous) $t(Common:Image)",
"Skip to first image": "Пропустить к первому $t(Common:Image)",
"Skip to last image": "Пропустить к последнему $t(Common:Image)",
"fps": "fps"
}
+20
View File
@@ -0,0 +1,20 @@
{
"Close": "Закрыть",
"Image": "Изображение",
"Last 30 days": "30 дней",
"Last 7 days": "7 дней",
"Layout": "Разбивка",
"Measurements": "Измерения",
"More": "Больше",
"Next": "Следующая",
"Play": "Проиграть",
"Previous": "Предыдущая",
"Reset": "Сбросить",
"RowsPerPage": "строк на странице",
"Series": "Серия",
"Show": "Показать",
"Stop": "Остановить",
"StudyDate": "Дата исследования",
"StudyList": "Список исследований",
"Today": "Сегодня"
}
@@ -0,0 +1,5 @@
{
"Clear dates": "Очистить даты",
"End Date": "Дата конца",
"Start Date": "Дата начала"
}
+8
View File
@@ -0,0 +1,8 @@
{
"About": "Справка",
"Back to Viewer": "Назад к Просмотрщику",
"INVESTIGATIONAL USE ONLY": "ТОЛЬКО ДЛЯ ИССЛЕДОВАНИЙ",
"Options": "Опции",
"Preferences": "Настройки",
"Study List": "Список исследований"
}
@@ -0,0 +1,11 @@
{
"Criteria nonconformities": "Критерии несоответствия",
"Delete": "Удалить",
"Description": "Описание",
"MAX": "МАКС",
"Measurements": "Измерения",
"NonTargets": "Нецелевые",
"Relabel": "Переназначить",
"StudyDate": "Дата исследования",
"Targets": "Цели"
}
@@ -0,0 +1,10 @@
{
"AccessionNumber": "Номер доступа",
"Description": "Описание",
"Empty": "Пусто",
"MRN": "MRN",
"Modality": "Модальность",
"PatientName": "Имя пациента",
"StudyDate": "Дата исследования",
"StudyDescription": "Описание"
}
@@ -0,0 +1,9 @@
{
"Cancel": "$t(Buttons:Cancel)",
"No hotkeys found": "Не найдено горячих клавиш",
"Reset to Defaults": "$t(Buttons:Reset to Defaults)",
"ResetDefaultMessage": "Настройки успешно сброшены. <br /> Вы должны <strong>Сохранить</strong> это действие нажав на кнопку.",
"Save": "$t(Buttons:Save)",
"SaveMessage": "Настройки сохранены",
"User Preferences": "Пользовательские настройки"
}
@@ -0,0 +1,14 @@
{
"emptyFilenameError": "Имя файла не может быть пустым.",
"fileType": "Тип файла",
"filename": "Имя файла",
"formTitle": "Пожалуйста, укажите разрешение, имя файла и желаемый тип изображения.",
"imageHeight": "Высота картинки (px)",
"imagePreview": "Предпросмотр",
"imageWidth": "Ширина картинки (px)",
"keepAspectRatio": "Сохранить соотношение сторон",
"loadingPreview": "Загружаю предпросмотр картинки...",
"minHeightError": "Минимальная высота - 100px.",
"minWidthError": "Минимальная ширина - 100px.",
"showAnnotations": "Показать аннотации"
}
+25
View File
@@ -0,0 +1,25 @@
import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
import UserPreferencesModal from './UserPreferencesModal.json';
import ViewportDownloadForm from './ViewportDownloadForm.json';
export default {
'ru': {
AboutModal,
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,
UserPreferencesModal,
ViewportDownloadForm,
}
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
Loaded 100 of 159 files, more files were not shown because too many files have changed in this diff. Show more