Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ee092bf2 | ||
|
|
e2f4f95222 | ||
|
|
4546ede9bb | ||
|
|
e0fb439e98 | ||
|
|
ebbc9e0d6d | ||
|
|
47a6130fd5 | ||
|
|
80dfdcc37c | ||
|
|
d74ad370e0 | ||
|
|
ddfde9279e | ||
|
|
aaab6d2622 | ||
|
|
d2921083e7 | ||
|
|
a6338ea266 | ||
|
|
fe9551b9b1 | ||
|
|
ef60156a47 | ||
|
|
850de2903a | ||
|
|
f26ed5539b | ||
|
|
21aeaa63c7 | ||
|
|
2ac0d3f017 | ||
|
|
efdbe8e7b4 | ||
|
|
67b70eaa98 | ||
|
|
5150ed9427 | ||
|
|
1bcb0acf9f | ||
|
|
5d6cf2a609 | ||
|
|
9f813e0ea0 | ||
|
|
49de44ba34 | ||
|
|
b04e186274 | ||
|
|
c59d66412f | ||
|
|
f8b4ccbb59 | ||
|
|
5426773ffc | ||
|
|
a507a00f59 | ||
|
|
cedeb756c0 | ||
|
|
64385485b6 | ||
|
|
32828d9a6e | ||
|
|
b94d4782d1 | ||
|
|
36b47ce3a3 | ||
|
|
fe57c00577 | ||
|
|
21a3bc2ded | ||
|
|
b6b09f22fc | ||
|
|
64a4d60e52 | ||
|
|
0ba796c73c | ||
|
|
cb7fafb1d6 | ||
|
|
7164d1a654 |
No files matched your search
+9
-13
@@ -27,7 +27,7 @@ executors:
|
|||||||
- image: 'cypress/browsers:node14.15.0-chrome86-ff82'
|
- image: 'cypress/browsers:node14.15.0-chrome86-ff82'
|
||||||
defaults: &defaults
|
defaults: &defaults
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:14.18
|
- image: cimg/node:14.19
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm # Enable colors in term
|
TERM: xterm # Enable colors in term
|
||||||
QUICK_BUILD: true
|
QUICK_BUILD: true
|
||||||
@@ -347,9 +347,8 @@ workflows:
|
|||||||
store_artifacts: true
|
store_artifacts: true
|
||||||
working_directory: platform/viewer
|
working_directory: platform/viewer
|
||||||
build:
|
build:
|
||||||
git submodule update --init &&
|
git submodule update --init && npx cross-env QUICK_BUILD=true
|
||||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
APP_CONFIG=config/e2e.js yarn run build
|
||||||
yarn run build
|
|
||||||
start: yarn run test:e2e:serve
|
start: yarn run test:e2e:serve
|
||||||
spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'
|
spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'
|
||||||
wait-on: 'http://localhost:3000'
|
wait-on: 'http://localhost:3000'
|
||||||
@@ -376,9 +375,8 @@ workflows:
|
|||||||
store_artifacts: true
|
store_artifacts: true
|
||||||
working_directory: platform/viewer
|
working_directory: platform/viewer
|
||||||
build:
|
build:
|
||||||
git submodule update --init &&
|
git submodule update --init && npx cross-env QUICK_BUILD=true
|
||||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
APP_CONFIG=config/e2e.js yarn run build:package
|
||||||
yarn run build:package
|
|
||||||
start: yarn run test:e2e:serve
|
start: yarn run test:e2e:serve
|
||||||
spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'
|
spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'
|
||||||
wait-on: 'http://localhost:3000'
|
wait-on: 'http://localhost:3000'
|
||||||
@@ -410,9 +408,8 @@ workflows:
|
|||||||
store_artifacts: false
|
store_artifacts: false
|
||||||
working_directory: platform/viewer
|
working_directory: platform/viewer
|
||||||
build:
|
build:
|
||||||
git submodule update --init &&
|
git submodule update --init && npx cross-env QUICK_BUILD=true
|
||||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
APP_CONFIG=config/e2e.js yarn run build
|
||||||
yarn run build
|
|
||||||
# start server --> verify running --> percy + chrome + cypress
|
# start server --> verify running --> percy + chrome + cypress
|
||||||
command: yarn run test:e2e:dist
|
command: yarn run test:e2e:dist
|
||||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||||
@@ -490,9 +487,8 @@ workflows:
|
|||||||
store_artifacts: false
|
store_artifacts: false
|
||||||
working_directory: platform/viewer
|
working_directory: platform/viewer
|
||||||
build:
|
build:
|
||||||
git submodule update --init &&
|
git submodule update --init && npx cross-env QUICK_BUILD=true
|
||||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
APP_CONFIG=config/e2e.js yarn run build
|
||||||
yarn run build
|
|
||||||
# start server --> verify running --> percy + chrome + cypress
|
# start server --> verify running --> percy + chrome + cypress
|
||||||
command: yarn run test:e2e:dist
|
command: yarn run test:e2e:dist
|
||||||
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ docs/_book
|
|||||||
src/version.js
|
src/version.js
|
||||||
junit.xml
|
junit.xml
|
||||||
coverage/
|
coverage/
|
||||||
.docz/
|
|
||||||
*.js.map
|
*.js.map
|
||||||
.yarn
|
.yarn
|
||||||
platform/docs/.docusaurus
|
platform/docs/.docusaurus
|
||||||
@@ -38,4 +37,3 @@ screenshots/
|
|||||||
|
|
||||||
# Locize settings
|
# Locize settings
|
||||||
.locize
|
.locize
|
||||||
|
|
||||||
@@ -22,16 +22,6 @@ mv platform/viewer/dist/* .netlify/www/pwa -v
|
|||||||
# Build && Move script output
|
# Build && Move script output
|
||||||
# yarn run build:package
|
# yarn run build:package
|
||||||
|
|
||||||
# Build && Move Docz Output
|
|
||||||
# Using local yarn install to prevent Gatsby from needing to access
|
|
||||||
# node_modules above the platform/ui folder
|
|
||||||
cd platform/ui
|
|
||||||
yarn install
|
|
||||||
yarn run build
|
|
||||||
cd ../..
|
|
||||||
mkdir -p ./.netlify/www/ui
|
|
||||||
mv platform/ui/.docz/dist/* .netlify/www/ui -v
|
|
||||||
|
|
||||||
# Cache all of the node_module dependencies in
|
# Cache all of the node_module dependencies in
|
||||||
# extensions, modules, and platform packages
|
# extensions, modules, and platform packages
|
||||||
yarn run lerna:cache
|
yarn run lerna:cache
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
# Stage 1: Build the application
|
# Stage 1: Build the application
|
||||||
# docker build -t ohif/viewer:latest .
|
# docker build -t ohif/viewer:latest .
|
||||||
FROM node:15.13.0-slim as builder
|
FROM node:14-slim as builder
|
||||||
|
|
||||||
RUN mkdir /usr/src/app
|
RUN mkdir /usr/src/app
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
@@ -42,7 +42,7 @@ COPY yarn.lock /usr/src/app/yarn.lock
|
|||||||
RUN apt-get update && apt-get install -y python make g++
|
RUN apt-get update && apt-get install -y python make g++
|
||||||
# Run the install before copying the rest of the files
|
# Run the install before copying the rest of the files
|
||||||
RUN yarn config set workspaces-experimental true
|
RUN yarn config set workspaces-experimental true
|
||||||
RUN yarn install
|
RUN yarn install --verbose
|
||||||
|
|
||||||
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||||
ENV QUICK_BUILD true
|
ENV QUICK_BUILD true
|
||||||
|
|||||||
@@ -3,6 +3,62 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.12.14](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.13...@ohif/extension-cornerstone@2.12.14) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.13](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.12...@ohif/extension-cornerstone@2.12.13) (2022-06-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.12](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.11...@ohif/extension-cornerstone@2.12.12) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.11](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.10...@ohif/extension-cornerstone@2.12.11) (2022-06-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.9...@ohif/extension-cornerstone@2.12.10) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.8...@ohif/extension-cornerstone@2.12.9) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.12.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.7...@ohif/extension-cornerstone@2.12.8) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.12.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.6...@ohif/extension-cornerstone@2.12.7) (2022-02-03)
|
## [2.12.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.12.6...@ohif/extension-cornerstone@2.12.7) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-cornerstone",
|
"name": "@ohif/extension-cornerstone",
|
||||||
"version": "2.12.7",
|
"version": "2.12.14",
|
||||||
"description": "OHIF extension for Cornerstone",
|
"description": "OHIF extension for Cornerstone",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"cornerstone-math": "^0.1.9",
|
"cornerstone-math": "^0.1.9",
|
||||||
"cornerstone-tools": "^6.0.6",
|
"cornerstone-tools": "^6.0.6",
|
||||||
"cornerstone-wado-image-loader": "^4.1.0",
|
"cornerstone-wado-image-loader": "^4.1.0",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"dicom-parser": "^1.8.11",
|
"dicom-parser": "^1.8.11",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
@@ -44,7 +44,8 @@
|
|||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-redux": "^6.0.0",
|
"react-redux": "^6.0.0",
|
||||||
"react-resize-detector": "^3.4.0",
|
"react-resize-detector": "^3.4.0",
|
||||||
"redux": "^4.0.1"
|
"redux": "^4.0.1",
|
||||||
|
"styled-components": "^5.3.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
|
|||||||
@@ -237,11 +237,21 @@ class OHIFCornerstoneViewport extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const warningsOverlay = props => {
|
const overlay = props => {
|
||||||
|
const displaySet = this.props.viewportData.displaySet;
|
||||||
|
let filteredSRLabels;
|
||||||
|
if (displaySet.SRLabels && displaySet.SRLabels.length !== 0) {
|
||||||
|
filteredSRLabels = displaySet.SRLabels.filter(
|
||||||
|
SRLabel =>
|
||||||
|
SRLabel.ReferencedSOPInstanceUID === displaySet.SOPInstanceUID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OHIFCornerstoneViewportOverlay
|
<OHIFCornerstoneViewportOverlay
|
||||||
{...props}
|
{...props}
|
||||||
inconsistencyWarnings={inconsistencyWarnings}
|
inconsistencyWarnings={inconsistencyWarnings}
|
||||||
|
SRLabels={filteredSRLabels}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -254,7 +264,7 @@ class OHIFCornerstoneViewport extends Component {
|
|||||||
imageIdIndex={currentImageIdIndex}
|
imageIdIndex={currentImageIdIndex}
|
||||||
onNewImageDebounced={newImageHandler}
|
onNewImageDebounced={newImageHandler}
|
||||||
onNewImageDebounceTime={300}
|
onNewImageDebounceTime={300}
|
||||||
viewportOverlayComponent={warningsOverlay}
|
viewportOverlayComponent={overlay}
|
||||||
stackPrefetch={this.props.stackPrefetch}
|
stackPrefetch={this.props.stackPrefetch}
|
||||||
isStackPrefetchEnabled={this.props.isStackPrefetchEnabled}
|
isStackPrefetchEnabled={this.props.isStackPrefetchEnabled}
|
||||||
// ~~ Connected (From REDUX)
|
// ~~ Connected (From REDUX)
|
||||||
|
|||||||
@@ -33,6 +33,10 @@
|
|||||||
bottom: 140px;
|
bottom: 140px;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
}
|
}
|
||||||
|
.OHIFCornerstoneViewportOverlay .bottom-left3 {
|
||||||
|
bottom: 110px;
|
||||||
|
left: -20px;
|
||||||
|
}
|
||||||
.OHIFCornerstoneViewportOverlay .bottom-right {
|
.OHIFCornerstoneViewportOverlay .bottom-right {
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cornerstone from 'cornerstone-core';
|
import cornerstone from 'cornerstone-core';
|
||||||
import './OHIFCornerstoneViewportOverlay.css';
|
import './OHIFCornerstoneViewportOverlay.css';
|
||||||
@@ -9,13 +10,27 @@ import {
|
|||||||
formatDICOMDate,
|
formatDICOMDate,
|
||||||
formatDICOMTime,
|
formatDICOMTime,
|
||||||
formatPN,
|
formatPN,
|
||||||
getCompression
|
getCompression,
|
||||||
} from '../utils/formatStudy';
|
} from '../utils/formatStudy';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Icon } from '@ohif/ui/src/elements/Icon';
|
import { Icon } from '@ohif/ui/src/elements/Icon';
|
||||||
import { Tooltip } from '@ohif/ui/src/components/tooltip';
|
import { Tooltip } from '@ohif/ui/src/components/tooltip';
|
||||||
import { OverlayTrigger } from '@ohif/ui/src/components/overlayTrigger';
|
import { OverlayTrigger } from '@ohif/ui/src/components/overlayTrigger';
|
||||||
|
|
||||||
|
const Button = styled.button`
|
||||||
|
color: white;
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
outline: 0;
|
||||||
|
text-transform: none;
|
||||||
|
margin: 2px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
class OHIFCornerstoneViewportOverlay extends PureComponent {
|
class OHIFCornerstoneViewportOverlay extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
scale: PropTypes.number.isRequired,
|
scale: PropTypes.number.isRequired,
|
||||||
@@ -30,11 +45,19 @@ class OHIFCornerstoneViewportOverlay extends PureComponent {
|
|||||||
imageId: PropTypes.string.isRequired,
|
imageId: PropTypes.string.isRequired,
|
||||||
imageIndex: PropTypes.number.isRequired,
|
imageIndex: PropTypes.number.isRequired,
|
||||||
stackSize: PropTypes.number.isRequired,
|
stackSize: PropTypes.number.isRequired,
|
||||||
inconsistencyWarnings: PropTypes.array.isRequired
|
inconsistencyWarnings: PropTypes.array,
|
||||||
|
SRLabels: PropTypes.array,
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { imageId, scale, windowWidth, windowCenter, inconsistencyWarnings } = this.props;
|
const {
|
||||||
|
imageId,
|
||||||
|
scale,
|
||||||
|
windowWidth,
|
||||||
|
windowCenter,
|
||||||
|
inconsistencyWarnings,
|
||||||
|
SRLabels,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (!imageId) {
|
if (!imageId) {
|
||||||
return null;
|
return null;
|
||||||
@@ -72,8 +95,11 @@ class OHIFCornerstoneViewportOverlay extends PureComponent {
|
|||||||
|
|
||||||
const { imageIndex, stackSize } = this.props;
|
const { imageIndex, stackSize } = this.props;
|
||||||
|
|
||||||
const inconsistencyWarningsOn = inconsistencyWarnings && inconsistencyWarnings.length !== 0 ? true : false;
|
const inconsistencyWarningsOn =
|
||||||
const getWarningContent = (warningList) => {
|
inconsistencyWarnings && inconsistencyWarnings.length !== 0
|
||||||
|
? true
|
||||||
|
: false;
|
||||||
|
const getWarningContent = warningList => {
|
||||||
if (Array.isArray(warningList)) {
|
if (Array.isArray(warningList)) {
|
||||||
const listedWarnings = warningList.map((warn, index) => {
|
const listedWarnings = warningList.map((warn, index) => {
|
||||||
return <li key={index}>{warn}</li>;
|
return <li key={index}>{warn}</li>;
|
||||||
@@ -86,33 +112,100 @@ class OHIFCornerstoneViewportOverlay extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getWarningInfo = (seriesNumber, inconsistencyWarnings) => {
|
const getWarningInfo = (seriesNumber, inconsistencyWarnings) => {
|
||||||
return(
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{inconsistencyWarnings.length != 0 ? (
|
{inconsistencyWarnings.length != 0 ? (
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
key={seriesNumber}
|
key={seriesNumber}
|
||||||
placement="left"
|
placement="left"
|
||||||
overlay={
|
overlay={
|
||||||
<Tooltip
|
<Tooltip
|
||||||
placement="left"
|
placement="left"
|
||||||
className="in tooltip-warning"
|
className="in tooltip-warning"
|
||||||
id="tooltip-left"
|
id="tooltip-left"
|
||||||
>
|
>
|
||||||
<div className="warningTitle">Series Inconsistencies</div>
|
<div className="warningTitle">Series Inconsistencies</div>
|
||||||
<div className="warningContent">{getWarningContent(inconsistencyWarnings)}</div>
|
<div className="warningContent">
|
||||||
</Tooltip>
|
{getWarningContent(inconsistencyWarnings)}
|
||||||
}
|
</div>
|
||||||
>
|
</Tooltip>
|
||||||
<div className={classNames('warning')}>
|
}
|
||||||
<span className="warning-icon">
|
>
|
||||||
<Icon name="exclamation-triangle" />
|
<div className={classNames('warning')}>
|
||||||
</span>
|
<span className="warning-icon">
|
||||||
</div>
|
<Icon name="exclamation-triangle" />
|
||||||
</OverlayTrigger>
|
</span>
|
||||||
) : (
|
</div>
|
||||||
<React.Fragment></React.Fragment>
|
</OverlayTrigger>
|
||||||
|
) : (
|
||||||
|
<React.Fragment></React.Fragment>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SRLabelsOn = SRLabels && SRLabels.length !== 0 ? true : false;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
|
||||||
|
const getSRLabelsContent = SRLabels => {
|
||||||
|
if (Array.isArray(SRLabels)) {
|
||||||
|
const listedSRLabels = SRLabels.map((SRLabel, index) => {
|
||||||
|
const color = SRLabel.labels.color;
|
||||||
|
return (
|
||||||
|
SRLabel.labels.visible && (
|
||||||
|
<OverlayTrigger
|
||||||
|
key={index}
|
||||||
|
placement="top"
|
||||||
|
overlay={
|
||||||
|
<Tooltip
|
||||||
|
placement="top"
|
||||||
|
className="in tooltip-warning"
|
||||||
|
id="tooltip-top"
|
||||||
|
>
|
||||||
|
<div className="warningTitle">
|
||||||
|
{' '}
|
||||||
|
Coding scheme designators{' '}
|
||||||
|
</div>
|
||||||
|
<div className="warningContent">
|
||||||
|
{SRLabel.labels.labelCodingSchemeDesignator +
|
||||||
|
' : ' +
|
||||||
|
SRLabel.labels.valueCodingSchemeDesignator}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'inline-block' }}>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
backgroundColor: color,
|
||||||
|
}}
|
||||||
|
disabled={true}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
{SRLabel.labels.label + ' : ' + SRLabel.labels.value}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return <ol>{listedSRLabels}</ol>;
|
||||||
|
} else {
|
||||||
|
return <React.Fragment></React.Fragment>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSRLabelsInfo = SRLabels => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{SRLabels.length != 0 ? (
|
||||||
|
getSRLabelsContent(SRLabels)
|
||||||
|
) : (
|
||||||
|
<React.Fragment></React.Fragment>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -134,7 +227,14 @@ class OHIFCornerstoneViewportOverlay extends PureComponent {
|
|||||||
<div className="compressionIndicator">{compression}</div>
|
<div className="compressionIndicator">{compression}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bottom-left2 warning">
|
<div className="bottom-left2 warning">
|
||||||
<div>{inconsistencyWarningsOn ? getWarningInfo(seriesNumber, inconsistencyWarnings) : ''}</div>
|
<div>
|
||||||
|
{inconsistencyWarningsOn
|
||||||
|
? getWarningInfo(seriesNumber, inconsistencyWarnings)
|
||||||
|
: ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom-left3 warning">
|
||||||
|
<div>{SRLabelsOn ? getSRLabelsInfo(SRLabels) : ''}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bottom-left overlay-element">
|
<div className="bottom-left overlay-element">
|
||||||
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
|
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
|||||||
const renderableDataForGraphicType = renderableData[GraphicType];
|
const renderableDataForGraphicType = renderableData[GraphicType];
|
||||||
|
|
||||||
switch (GraphicType) {
|
switch (GraphicType) {
|
||||||
|
case SCOORD_TYPES.TEXT:
|
||||||
|
break;
|
||||||
case SCOORD_TYPES.POINT:
|
case SCOORD_TYPES.POINT:
|
||||||
this.renderPoint(renderableDataForGraphicType, eventData, options);
|
this.renderPoint(renderableDataForGraphicType, eventData, options);
|
||||||
break;
|
break;
|
||||||
@@ -167,20 +169,22 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
|||||||
return data.handles.textBox.anchorPoints;
|
return data.handles.textBox.anchorPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(context, context => {
|
if (data.handles.textBox.anchorPoints.length !== 0) {
|
||||||
drawLinkedTextBox(
|
draw(context, context => {
|
||||||
context,
|
drawLinkedTextBox(
|
||||||
element,
|
context,
|
||||||
data.handles.textBox,
|
element,
|
||||||
text,
|
data.handles.textBox,
|
||||||
data.handles,
|
text,
|
||||||
textBoxAnchorPoints,
|
data.handles,
|
||||||
color,
|
textBoxAnchorPoints,
|
||||||
lineWidth,
|
color,
|
||||||
0,
|
lineWidth,
|
||||||
true
|
0,
|
||||||
);
|
true
|
||||||
});
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOOD -> text boxes may overlap with other annotations at the moment.
|
// TOOD -> text boxes may overlap with other annotations at the moment.
|
||||||
@@ -230,7 +234,6 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
|||||||
const { element, image } = eventData;
|
const { element, image } = eventData;
|
||||||
const { rows, columns } = image;
|
const { rows, columns } = image;
|
||||||
const context = getNewContext(eventData.canvasContext.canvas);
|
const context = getNewContext(eventData.canvasContext.canvas);
|
||||||
|
|
||||||
const { color, lineWidth } = options;
|
const { color, lineWidth } = options;
|
||||||
|
|
||||||
// Find a suitable length for the image size.
|
// Find a suitable length for the image size.
|
||||||
@@ -332,6 +335,8 @@ function _getTextBoxAnchorPointsForRenderableData(renderableData, eventData) {
|
|||||||
const renderableDataForGraphicType = renderableData[GraphicType];
|
const renderableDataForGraphicType = renderableData[GraphicType];
|
||||||
|
|
||||||
switch (GraphicType) {
|
switch (GraphicType) {
|
||||||
|
case SCOORD_TYPES.TEXT:
|
||||||
|
break;
|
||||||
case SCOORD_TYPES.POINT:
|
case SCOORD_TYPES.POINT:
|
||||||
renderableDataForGraphicType.forEach(points => {
|
renderableDataForGraphicType.forEach(points => {
|
||||||
anchorPoints = [...anchorPoints, ...points];
|
anchorPoints = [...anchorPoints, ...points];
|
||||||
@@ -405,7 +410,7 @@ function _getBoundingBoxFromAnchorPoints(anchorPoints) {
|
|||||||
minX = x;
|
minX = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y > maxX) {
|
if (y > maxY) {
|
||||||
maxY = y;
|
maxY = y;
|
||||||
} else if (y < minY) {
|
} else if (y < minY) {
|
||||||
minY = y;
|
minY = y;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
|
TEXT: 'TEXT',
|
||||||
POINT: 'POINT',
|
POINT: 'POINT',
|
||||||
MULTIPOINT: 'MULTIPOINT',
|
MULTIPOINT: 'MULTIPOINT',
|
||||||
POLYLINE: 'POLYLINE',
|
POLYLINE: 'POLYLINE',
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.3.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.3.2...@ohif/extension-debugging@0.3.3) (2022-06-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-debugging
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.3.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.3.1...@ohif/extension-debugging@0.3.2) (2022-03-10)
|
## [0.3.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.3.1...@ohif/extension-debugging@0.3.2) (2022-03-10)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-debugging
|
**Note:** Version bump only for package @ohif/extension-debugging
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-debugging",
|
"name": "@ohif/extension-debugging",
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"description": "OHIF extension for debugging.",
|
"description": "OHIF extension for debugging.",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -89,10 +89,10 @@ const DubugReportModal = ({
|
|||||||
|
|
||||||
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
||||||
const displaySet = viewportSpecificData[viewportIndex];
|
const displaySet = viewportSpecificData[viewportIndex];
|
||||||
const [
|
const [referencedDisplaySetsRef] = _getReferencedSeriesInstanceUIDsString(
|
||||||
referencedDisplaySetsRef,
|
displaySet,
|
||||||
referencedDisplaySetsCount,
|
'SEG'
|
||||||
] = _getReferencedSeriesInstanceUIDsString(displaySet, 'SEG');
|
);
|
||||||
|
|
||||||
const [row, column] = _viewportIndexToViewportPosition(
|
const [row, column] = _viewportIndexToViewportPosition(
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
@@ -106,10 +106,27 @@ const DubugReportModal = ({
|
|||||||
|
|
||||||
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
||||||
const displaySet = viewportSpecificData[viewportIndex];
|
const displaySet = viewportSpecificData[viewportIndex];
|
||||||
const [
|
const [referencedDisplaySetsRef] = _getReferencedSeriesInstanceUIDsString(
|
||||||
referencedDisplaySetsRef,
|
displaySet,
|
||||||
referencedDisplaySetsCount,
|
'RTSTRUCT'
|
||||||
] = _getReferencedSeriesInstanceUIDsString(displaySet, 'RTSTRUCT');
|
);
|
||||||
|
|
||||||
|
const [row, column] = _viewportIndexToViewportPosition(
|
||||||
|
viewportIndex,
|
||||||
|
numColumns
|
||||||
|
);
|
||||||
|
|
||||||
|
body += `[${row},${column}]\t${referencedDisplaySetsRef}\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
body += '== ReferencedSRSeriesInstanceUIDs ==\n';
|
||||||
|
|
||||||
|
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
||||||
|
const displaySet = viewportSpecificData[viewportIndex];
|
||||||
|
const [referencedDisplaySetsRef] = _getReferencedSeriesInstanceUIDsString(
|
||||||
|
displaySet,
|
||||||
|
'SR'
|
||||||
|
);
|
||||||
|
|
||||||
const [row, column] = _viewportIndexToViewportPosition(
|
const [row, column] = _viewportIndexToViewportPosition(
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
@@ -261,11 +278,15 @@ const getLayout = viewports => {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>ReferencedSEGSeriesInstanceUIDs</th>
|
<th>ReferencedSEGSeriesInstanceUIDs</th>
|
||||||
</tr>
|
</tr>
|
||||||
{getReferencedSEGSeriesInstanceUIDsPerRow(viewports)}
|
{getReferencedSeriesInstanceUIDsPerRow(viewports, 'SEG')}
|
||||||
<tr>
|
<tr>
|
||||||
<th>ReferencedRTSTRUCTSeriesInstanceUIDs</th>
|
<th>ReferencedRTSTRUCTSeriesInstanceUIDs</th>
|
||||||
</tr>
|
</tr>
|
||||||
{getReferencedRTSTRUCTSeriesInstanceUIDsPerRow(viewports)}
|
{getReferencedSeriesInstanceUIDsPerRow(viewports, 'RTSTRUCT')}
|
||||||
|
<tr>
|
||||||
|
<th>ReferencedSRSeriesInstanceUIDs</th>
|
||||||
|
</tr>
|
||||||
|
{getReferencedSeriesInstanceUIDsPerRow(viewports, 'SR')}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -351,7 +372,7 @@ const _getReferencedSeriesInstanceUIDsString = (displaySet, Modality) => {
|
|||||||
return [referencedDisplaySetsRef, referencedDisplaySetsCount];
|
return [referencedDisplaySetsRef, referencedDisplaySetsCount];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getReferencedSEGSeriesInstanceUIDsPerRow = viewports => {
|
const getReferencedSeriesInstanceUIDsPerRow = (viewports, Modality) => {
|
||||||
const { viewportSpecificData, numColumns } = viewports;
|
const { viewportSpecificData, numColumns } = viewports;
|
||||||
|
|
||||||
// NOTE viewportSpecificData is actually an object with numerical keys.
|
// NOTE viewportSpecificData is actually an object with numerical keys.
|
||||||
@@ -360,43 +381,7 @@ const getReferencedSEGSeriesInstanceUIDsPerRow = viewports => {
|
|||||||
const [
|
const [
|
||||||
referencedDisplaySetsRef,
|
referencedDisplaySetsRef,
|
||||||
referencedDisplaySetsCount,
|
referencedDisplaySetsCount,
|
||||||
] = _getReferencedSeriesInstanceUIDsString(displaySet, 'SEG');
|
] = _getReferencedSeriesInstanceUIDsString(displaySet, Modality);
|
||||||
|
|
||||||
const [row, column] = _viewportIndexToViewportPosition(
|
|
||||||
viewportIndex,
|
|
||||||
numColumns
|
|
||||||
);
|
|
||||||
|
|
||||||
if (referencedDisplaySetsCount > 1) {
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td>{`[${row},${column}]`}</td>
|
|
||||||
<td className="debug-overflowText-border">
|
|
||||||
{referencedDisplaySetsRef}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td>{`[${row},${column}]`}</td>
|
|
||||||
<td className="debug-overflowText">{referencedDisplaySetsRef}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getReferencedRTSTRUCTSeriesInstanceUIDsPerRow = viewports => {
|
|
||||||
const { viewportSpecificData, numColumns } = viewports;
|
|
||||||
|
|
||||||
// NOTE viewportSpecificData is actually an object with numerical keys.
|
|
||||||
return Object.keys(viewportSpecificData).map(viewportIndex => {
|
|
||||||
const displaySet = viewportSpecificData[viewportIndex];
|
|
||||||
const [
|
|
||||||
referencedDisplaySetsRef,
|
|
||||||
referencedDisplaySetsCount,
|
|
||||||
] = _getReferencedSeriesInstanceUIDsString(displaySet, 'RTSTRUCT');
|
|
||||||
|
|
||||||
const [row, column] = _viewportIndexToViewportPosition(
|
const [row, column] = _viewportIndexToViewportPosition(
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.3.23](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.22...@ohif/extension-dicom-html@1.3.23) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.3.22](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.21...@ohif/extension-dicom-html@1.3.22) (2022-06-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.3.21](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.20...@ohif/extension-dicom-html@1.3.21) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.3.20](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.19...@ohif/extension-dicom-html@1.3.20) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.3.19](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.18...@ohif/extension-dicom-html@1.3.19) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.3.18](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.17...@ohif/extension-dicom-html@1.3.18) (2022-02-03)
|
## [1.3.18](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.17...@ohif/extension-dicom-html@1.3.18) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-html",
|
"name": "@ohif/extension-dicom-html",
|
||||||
"version": "1.3.18",
|
"version": "1.3.23",
|
||||||
"description": "OHIF extension for rendering structured reports to HTML",
|
"description": "OHIF extension for rendering structured reports to HTML",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MODULE_TYPES, utils } from '@ohif/core';
|
import { MODULE_TYPES, utils, metadata } from '@ohif/core';
|
||||||
|
|
||||||
// TODO: Should probably use dcmjs for this
|
// TODO: Should probably use dcmjs for this
|
||||||
const SOP_CLASS_UIDS = {
|
const SOP_CLASS_UIDS = {
|
||||||
@@ -10,7 +10,7 @@ const SOP_CLASS_UIDS = {
|
|||||||
MAMMOGRAPHY_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.50',
|
MAMMOGRAPHY_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.50',
|
||||||
CHEST_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.65',
|
CHEST_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.65',
|
||||||
X_RAY_RADIATION_DOSE_SR: '1.2.840.10008.5.1.4.1.1.88.67',
|
X_RAY_RADIATION_DOSE_SR: '1.2.840.10008.5.1.4.1.1.88.67',
|
||||||
ACQUISITION_CONTEXT_SR_STORAGE: '1.2.840.10008.5.1.4.1.1.88.71'
|
ACQUISITION_CONTEXT_SR_STORAGE: '1.2.840.10008.5.1.4.1.1.88.71',
|
||||||
};
|
};
|
||||||
|
|
||||||
const sopClassUIDs = Object.values(SOP_CLASS_UIDS);
|
const sopClassUIDs = Object.values(SOP_CLASS_UIDS);
|
||||||
@@ -32,7 +32,7 @@ const OHIFDicomHtmlSopClassHandler = {
|
|||||||
SeriesTime,
|
SeriesTime,
|
||||||
} = metadata;
|
} = metadata;
|
||||||
|
|
||||||
return {
|
const srDisplaySet = {
|
||||||
plugin: 'html',
|
plugin: 'html',
|
||||||
Modality: 'SR',
|
Modality: 'SR',
|
||||||
displaySetInstanceUID: utils.guid(),
|
displaySetInstanceUID: utils.guid(),
|
||||||
@@ -49,7 +49,15 @@ const OHIFDicomHtmlSopClassHandler = {
|
|||||||
authorizationHeaders,
|
authorizationHeaders,
|
||||||
sopClassUids: sopClassUIDs,
|
sopClassUids: sopClassUIDs,
|
||||||
images: series._instances,
|
images: series._instances,
|
||||||
|
isDerived: true,
|
||||||
|
referencedDisplaySets: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
srDisplaySet.getSourceDisplaySet = function() {
|
||||||
|
return srDisplaySet.referencedDisplaySets;
|
||||||
|
};
|
||||||
|
|
||||||
|
return srDisplaySet;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.7.13](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.12...@ohif/extension-dicom-rt@0.7.13) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.12](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.11...@ohif/extension-dicom-rt@0.7.12) (2022-08-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.11](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.10...@ohif/extension-dicom-rt@0.7.11) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.9...@ohif/extension-dicom-rt@0.7.10) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.8...@ohif/extension-dicom-rt@0.7.9) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.7.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.7...@ohif/extension-dicom-rt@0.7.8) (2022-02-03)
|
## [0.7.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.7.7...@ohif/extension-dicom-rt@0.7.8) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
**Note:** Version bump only for package @ohif/extension-dicom-rt
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-rt",
|
"name": "@ohif/extension-dicom-rt",
|
||||||
"version": "0.7.8",
|
"version": "0.7.13",
|
||||||
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
|
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.6.1",
|
"cornerstone-core": "^2.6.1",
|
||||||
"cornerstone-tools": "^6.0.6",
|
"cornerstone-tools": "^6.0.6",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"gl-matrix": "^3.3.0",
|
"gl-matrix": "^3.3.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cornerstoneTools from 'cornerstone-tools';
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
import cornerstone from 'cornerstone-core';
|
import cornerstone from 'cornerstone-core';
|
||||||
|
|||||||
@@ -3,6 +3,62 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.7.15](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.14...@ohif/extension-dicom-segmentation@0.7.15) (2022-09-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.14](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.13...@ohif/extension-dicom-segmentation@0.7.14) (2022-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.13](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.12...@ohif/extension-dicom-segmentation@0.7.13) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.12](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.11...@ohif/extension-dicom-segmentation@0.7.12) (2022-08-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.11](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.10...@ohif/extension-dicom-segmentation@0.7.11) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.9...@ohif/extension-dicom-segmentation@0.7.10) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.8...@ohif/extension-dicom-segmentation@0.7.9) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.7.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.7...@ohif/extension-dicom-segmentation@0.7.8) (2022-02-03)
|
## [0.7.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.7.7...@ohif/extension-dicom-segmentation@0.7.8) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-segmentation",
|
"name": "@ohif/extension-dicom-segmentation",
|
||||||
"version": "0.7.8",
|
"version": "0.7.15",
|
||||||
"description": "OHIF extension for viewing segmentations in the 2D MPR view",
|
"description": "OHIF extension for viewing segmentations in the 2D MPR view",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.6.1",
|
"cornerstone-core": "^2.6.1",
|
||||||
"cornerstone-tools": "^6.0.6",
|
"cornerstone-tools": "^6.0.6",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
+30
-21
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cornerstoneTools from 'cornerstone-tools';
|
import cornerstoneTools from 'cornerstone-tools';
|
||||||
import cornerstone from 'cornerstone-core';
|
import cornerstone from 'cornerstone-core';
|
||||||
@@ -36,6 +36,7 @@ const { studyMetadataManager } = utils;
|
|||||||
* @param {Function} props.onConfigurationChange - Configuration change handler
|
* @param {Function} props.onConfigurationChange - Configuration change handler
|
||||||
* @param {Function} props.activeContexts - List of active application contexts
|
* @param {Function} props.activeContexts - List of active application contexts
|
||||||
* @param {Function} props.contexts - List of available application contexts
|
* @param {Function} props.contexts - List of available application contexts
|
||||||
|
* @param {Function} props.servicesManager - Services manager
|
||||||
* @returns component
|
* @returns component
|
||||||
*/
|
*/
|
||||||
const SegmentationPanel = ({
|
const SegmentationPanel = ({
|
||||||
@@ -50,6 +51,7 @@ const SegmentationPanel = ({
|
|||||||
onSelectedSegmentationChange,
|
onSelectedSegmentationChange,
|
||||||
activeContexts = [],
|
activeContexts = [],
|
||||||
contexts = {},
|
contexts = {},
|
||||||
|
servicesManager,
|
||||||
}) => {
|
}) => {
|
||||||
const isVTK = () => activeContexts.includes(contexts.VTK);
|
const isVTK = () => activeContexts.includes(contexts.VTK);
|
||||||
const isCornerstone = () => activeContexts.includes(contexts.CORNERSTONE);
|
const isCornerstone = () => activeContexts.includes(contexts.CORNERSTONE);
|
||||||
@@ -59,6 +61,9 @@ const SegmentationPanel = ({
|
|||||||
* store with context to make these kind of things less blurry.
|
* store with context to make these kind of things less blurry.
|
||||||
*/
|
*/
|
||||||
const { configuration } = cornerstoneTools.getModule('segmentation');
|
const { configuration } = cornerstoneTools.getModule('segmentation');
|
||||||
|
if (configuration.segsTolerance === undefined) {
|
||||||
|
configuration.segsTolerance = 1e-2;
|
||||||
|
}
|
||||||
const DEFAULT_BRUSH_RADIUS = configuration.radius || 10;
|
const DEFAULT_BRUSH_RADIUS = configuration.radius || 10;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,6 +92,25 @@ const SegmentationPanel = ({
|
|||||||
return studyMetadata.getFirstImageId(displaySetInstanceUID);
|
return studyMetadata.getFirstImageId(displaySetInstanceUID);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAllSegDisplaySets = () => {
|
||||||
|
const { StudyInstanceUID } = getActiveViewport();
|
||||||
|
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
|
||||||
|
return studyMetadata.getDerivedDatasets({
|
||||||
|
Modality: 'SEG',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSegDisplaySetsTolerance = tolerance => {
|
||||||
|
const segDisplaySets = getAllSegDisplaySets();
|
||||||
|
segDisplaySets.forEach(segDisplaySet => {
|
||||||
|
// update tol value
|
||||||
|
segDisplaySet.tolerance = tolerance;
|
||||||
|
// reset load flags for allowing retry for seg parsing.
|
||||||
|
segDisplaySet.isLoaded = false;
|
||||||
|
segDisplaySet.loadError = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getActiveLabelMaps3D = () => {
|
const getActiveLabelMaps3D = () => {
|
||||||
const { labelmaps3D, activeLabelmapIndex } = getBrushStackState();
|
const { labelmaps3D, activeLabelmapIndex } = getBrushStackState();
|
||||||
return labelmaps3D[activeLabelmapIndex];
|
return labelmaps3D[activeLabelmapIndex];
|
||||||
@@ -224,33 +248,15 @@ const SegmentationPanel = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}, [
|
}, [activeIndex, viewports]);
|
||||||
activeIndex,
|
|
||||||
updateSegmentationComboBox,
|
|
||||||
viewports,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const updateSegmentationComboBox = e => {
|
const updateSegmentationComboBox = e => {
|
||||||
const index = e.detail.activatedLabelmapIndex;
|
const index = e.detail.activatedLabelmapIndex;
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
setState(state => ({ ...state, selectedSegmentation: index }));
|
setState(state => ({ ...state, selectedSegmentation: index }));
|
||||||
} else {
|
|
||||||
cleanSegmentationComboBox();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cleanSegmentationComboBox = () => {
|
|
||||||
setState(state => ({
|
|
||||||
...state,
|
|
||||||
segmentsHidden: [],
|
|
||||||
segmentNumbers: [],
|
|
||||||
labelMapList: [],
|
|
||||||
segmentList: [],
|
|
||||||
isDisabled: true,
|
|
||||||
selectedSegmentation: -1,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshSegmentations = () => {
|
const refreshSegmentations = () => {
|
||||||
const activeViewport = getActiveViewport();
|
const activeViewport = getActiveViewport();
|
||||||
const isDisabled = !activeViewport || !activeViewport.StudyInstanceUID;
|
const isDisabled = !activeViewport || !activeViewport.StudyInstanceUID;
|
||||||
@@ -616,7 +622,9 @@ const SegmentationPanel = ({
|
|||||||
configuration.outlineWidth = newConfiguration.outlineWidth;
|
configuration.outlineWidth = newConfiguration.outlineWidth;
|
||||||
configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive;
|
configuration.fillAlphaInactive = newConfiguration.fillAlphaInactive;
|
||||||
configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive;
|
configuration.outlineAlphaInactive = newConfiguration.outlineAlphaInactive;
|
||||||
|
configuration.segsTolerance = newConfiguration.segsTolerance;
|
||||||
onConfigurationChange(newConfiguration);
|
onConfigurationChange(newConfiguration);
|
||||||
|
updateSegDisplaySetsTolerance(configuration.segsTolerance);
|
||||||
refreshViewports();
|
refreshViewports();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -665,6 +673,7 @@ const SegmentationPanel = ({
|
|||||||
configuration={configuration}
|
configuration={configuration}
|
||||||
onBack={() => setState(state => ({ ...state, showSettings: false }))}
|
onBack={() => setState(state => ({ ...state, showSettings: false }))}
|
||||||
onChange={updateConfiguration}
|
onChange={updateConfiguration}
|
||||||
|
servicesManager={servicesManager}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -709,7 +718,7 @@ const SegmentationPanel = ({
|
|||||||
count={state.segmentList.length}
|
count={state.segmentList.length}
|
||||||
isVisible={
|
isVisible={
|
||||||
state.segmentsHidden.filter(isHidden => isHidden === true).length <
|
state.segmentsHidden.filter(isHidden => isHidden === true).length <
|
||||||
state.segmentNumbers.length
|
state.segmentNumbers.length && state.segmentNumbers.length > 0
|
||||||
}
|
}
|
||||||
onVisibilityChange={onVisibilityChangeHandler}
|
onVisibilityChange={onVisibilityChangeHandler}
|
||||||
>
|
>
|
||||||
|
|||||||
+42
-6
@@ -4,7 +4,7 @@ import { Range } from '@ohif/ui';
|
|||||||
|
|
||||||
import './SegmentationSettings.css';
|
import './SegmentationSettings.css';
|
||||||
|
|
||||||
const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields = [] }) => {
|
const SegmentationSettings = ({ configuration, onBack, onChange, servicesManager, disabledFields = [] }) => {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
renderFill: configuration.renderFill,
|
renderFill: configuration.renderFill,
|
||||||
renderOutline: configuration.renderOutline,
|
renderOutline: configuration.renderOutline,
|
||||||
@@ -13,7 +13,8 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields
|
|||||||
outlineAlpha: configuration.outlineAlpha,
|
outlineAlpha: configuration.outlineAlpha,
|
||||||
outlineWidth: configuration.outlineWidth,
|
outlineWidth: configuration.outlineWidth,
|
||||||
fillAlphaInactive: configuration.fillAlphaInactive,
|
fillAlphaInactive: configuration.fillAlphaInactive,
|
||||||
outlineAlphaInactive: configuration.outlineAlphaInactive
|
outlineAlphaInactive: configuration.outlineAlphaInactive,
|
||||||
|
segsTolerance: configuration.segsTolerance,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -133,6 +134,40 @@ const SegmentationSettings = ({ configuration, onBack, onChange, disabledFields
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="settings-group" style={{ marginBottom: 15 }}>
|
||||||
|
<label style={{ margin: '0 15px' }}>
|
||||||
|
Tolerance:
|
||||||
|
<input
|
||||||
|
style={{ margin: '0 15px' }}
|
||||||
|
label="Tolerance"
|
||||||
|
onKeyPress={event => {
|
||||||
|
const validate = string => {
|
||||||
|
let rgx = /[^-.e0-9]+/g;
|
||||||
|
return string.match(rgx);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (validate(event.key)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onChange={event => {
|
||||||
|
save('segsTolerance', event.target.value);
|
||||||
|
|
||||||
|
const { UINotificationService, LoggerService } = servicesManager.services;
|
||||||
|
const error = new Error('Segmentation loader tolerance changed. This operation can potentially generate errors in the Segmentation parsing.');
|
||||||
|
LoggerService.error({ error, message: error.message });
|
||||||
|
UINotificationService.show({
|
||||||
|
title: 'Segmentation panel',
|
||||||
|
message: error.message,
|
||||||
|
type: 'warning',
|
||||||
|
autoClose: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value={state.segsTolerance}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -169,11 +204,12 @@ SegmentationSettings.propTypes = {
|
|||||||
renderFill: PropTypes.bool.isRequired,
|
renderFill: PropTypes.bool.isRequired,
|
||||||
renderOutline: PropTypes.bool.isRequired,
|
renderOutline: PropTypes.bool.isRequired,
|
||||||
shouldRenderInactiveLabelmaps: PropTypes.bool.isRequired,
|
shouldRenderInactiveLabelmaps: PropTypes.bool.isRequired,
|
||||||
fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */
|
fillAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, /* TODO: why fillAlpha is string? */
|
outlineAlpha: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
outlineWidth: PropTypes.number.isRequired,
|
outlineWidth: PropTypes.number.isRequired,
|
||||||
fillAlphaInactive: PropTypes.number.isRequired,
|
fillAlphaInactive: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
outlineAlphaInactive: PropTypes.number.isRequired,
|
outlineAlphaInactive: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
segsTolerance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
onBack: PropTypes.func.isRequired,
|
onBack: PropTypes.func.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
SeriesNumber,
|
SeriesNumber,
|
||||||
SeriesDescription,
|
SeriesDescription,
|
||||||
metadata,
|
metadata,
|
||||||
|
tolerance: 1e-2,
|
||||||
};
|
};
|
||||||
|
|
||||||
segDisplaySet.getSourceDisplaySet = function(
|
segDisplaySet.getSourceDisplaySet = function(
|
||||||
@@ -93,7 +94,7 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
referencedDisplaySet.SeriesInstanceUID
|
referencedDisplaySet.SeriesInstanceUID
|
||||||
);
|
);
|
||||||
|
|
||||||
const results = await _parseSeg(segArrayBuffer, imageIds);
|
const results = await _parseSeg(segArrayBuffer, imageIds, segDisplaySet.tolerance);
|
||||||
if (results === undefined) {
|
if (results === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -149,10 +150,13 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _parseSeg(arrayBuffer, imageIds) {
|
function _parseSeg(
|
||||||
const skipOverlapping = false;
|
arrayBuffer,
|
||||||
const tolerance = 1e-2;
|
imageIds,
|
||||||
const cornerstoneToolsVersion = 4;
|
tolerance = 1e-2,
|
||||||
|
skipOverlapping = false,
|
||||||
|
cornerstoneToolsVersion = 4
|
||||||
|
) {
|
||||||
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
|
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
|
||||||
imageIds,
|
imageIds,
|
||||||
arrayBuffer,
|
arrayBuffer,
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export default {
|
|||||||
|
|
||||||
const ExtendedSegmentationPanel = props => {
|
const ExtendedSegmentationPanel = props => {
|
||||||
const { activeContexts } = api.hooks.useAppContext();
|
const { activeContexts } = api.hooks.useAppContext();
|
||||||
|
|
||||||
const onDisplaySetLoadFailureHandler = error => {
|
const onDisplaySetLoadFailureHandler = error => {
|
||||||
LoggerService.error({ error, message: error.message });
|
LoggerService.error({ error, message: error.message });
|
||||||
UINotificationService.show({
|
UINotificationService.show({
|
||||||
@@ -78,6 +77,7 @@ export default {
|
|||||||
onConfigurationChange={onConfigurationChangeHandler}
|
onConfigurationChange={onConfigurationChangeHandler}
|
||||||
onSelectedSegmentationChange={onSelectedSegmentationChangeHandler}
|
onSelectedSegmentationChange={onSelectedSegmentationChangeHandler}
|
||||||
onDisplaySetLoadFailure={onDisplaySetLoadFailureHandler}
|
onDisplaySetLoadFailure={onDisplaySetLoadFailureHandler}
|
||||||
|
servicesManager={servicesManager}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,14 +47,23 @@ export default async function setActiveLabelmap(
|
|||||||
return labelmapIndex;
|
return labelmapIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!displaySet.isLoaded) {
|
if (!displaySet.isLoaded && !displaySet.loadError) {
|
||||||
try {
|
try {
|
||||||
await displaySet.load(referencedDisplaySet, studies);
|
await displaySet.load(referencedDisplaySet, studies);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
displaySet.isLoaded = false;
|
displaySet.isLoaded = false;
|
||||||
displaySet.loadError = true;
|
displaySet.loadError = true;
|
||||||
|
displaySet.segLoadErrorMessagge = error.message;
|
||||||
onDisplaySetLoadFailure(error);
|
onDisplaySetLoadFailure(error);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Improve the way we notify parts of the app
|
||||||
|
* that depends on derived display sets to be loaded.
|
||||||
|
* (Implement pubsub for better tracking of derived display sets)
|
||||||
|
*/
|
||||||
|
const event = new CustomEvent('segmentationLoadingError');
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.2.24](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.23...@ohif/extension-dicom-tag-browser@0.2.24) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.23](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.22...@ohif/extension-dicom-tag-browser@0.2.23) (2022-04-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.22](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.21...@ohif/extension-dicom-tag-browser@0.2.22) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.21](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.20...@ohif/extension-dicom-tag-browser@0.2.21) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.20](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.19...@ohif/extension-dicom-tag-browser@0.2.20) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.2.19](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.18...@ohif/extension-dicom-tag-browser@0.2.19) (2022-02-03)
|
## [0.2.19](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.18...@ohif/extension-dicom-tag-browser@0.2.19) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-dicom-tag-browser",
|
"name": "@ohif/extension-dicom-tag-browser",
|
||||||
"version": "0.2.19",
|
"version": "0.2.24",
|
||||||
"description": "OHIF extension for checking DICOM headers.",
|
"description": "OHIF extension for checking DICOM headers.",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^2.6.0",
|
"@ohif/core": "^2.6.0",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"react": "^16.8.6"
|
"react": "^16.8.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
|||||||
let metadata;
|
let metadata;
|
||||||
const isImageStack =
|
const isImageStack =
|
||||||
activeDisplaySet instanceof ImageSet &&
|
activeDisplaySet instanceof ImageSet &&
|
||||||
activeDisplaySet.isModalitySupported === true;
|
activeDisplaySet.isSOPClassUIDSupported === true;
|
||||||
|
|
||||||
let instanceList;
|
let instanceList;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.2.1...@ohif/extension-lesion-tracker@0.2.2) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-lesion-tracker
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.2.0...@ohif/extension-lesion-tracker@0.2.1) (2020-09-03)
|
## [0.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-lesion-tracker@0.2.0...@ohif/extension-lesion-tracker@0.2.1) (2020-09-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-lesion-tracker
|
**Note:** Version bump only for package @ohif/extension-lesion-tracker
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-lesion-tracker",
|
"name": "@ohif/extension-lesion-tracker",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "OHIF extension for Lesion Tracker",
|
"description": "OHIF extension for Lesion Tracker",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ const additionalFindings = [
|
|||||||
|
|
||||||
const currentCollections = [
|
const currentCollections = [
|
||||||
{
|
{
|
||||||
selectorAction: () => { },
|
selectorAction: () => {},
|
||||||
maxMeasurements: 3,
|
maxMeasurements: 3,
|
||||||
groupName: 'Measurements',
|
groupName: 'Measurements',
|
||||||
measurements: measurements,
|
measurements: measurements,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectorAction: () => { },
|
selectorAction: () => {},
|
||||||
groupName: 'Additional Findings',
|
groupName: 'Additional Findings',
|
||||||
measurements: additionalFindings,
|
measurements: additionalFindings,
|
||||||
},
|
},
|
||||||
@@ -90,13 +90,13 @@ const currentCollections = [
|
|||||||
|
|
||||||
const comparisonColletions = [
|
const comparisonColletions = [
|
||||||
{
|
{
|
||||||
selectorAction: () => { },
|
selectorAction: () => {},
|
||||||
maxMeasurements: 3,
|
maxMeasurements: 3,
|
||||||
groupName: 'Measurements',
|
groupName: 'Measurements',
|
||||||
measurements: measurements,
|
measurements: measurements,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectorAction: () => { },
|
selectorAction: () => {},
|
||||||
groupName: 'Additional Findings',
|
groupName: 'Additional Findings',
|
||||||
measurements: additionalFindings,
|
measurements: additionalFindings,
|
||||||
},
|
},
|
||||||
@@ -128,7 +128,7 @@ const comparisonTimepoints = [
|
|||||||
{
|
{
|
||||||
key: 'Comparison',
|
key: 'Comparison',
|
||||||
date: '15-Jun-18',
|
date: '15-Jun-18',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const MeasurementComparisonTable = () => {
|
const MeasurementComparisonTable = () => {
|
||||||
@@ -138,8 +138,8 @@ const MeasurementComparisonTable = () => {
|
|||||||
timepoints={comparisonTimepoints}
|
timepoints={comparisonTimepoints}
|
||||||
overallWarnings={overallWarnings}
|
overallWarnings={overallWarnings}
|
||||||
measurementCollection={comparisonCollections}
|
measurementCollection={comparisonCollections}
|
||||||
onRelabelClick={() => { }}
|
onRelabelClick={() => {}}
|
||||||
onEditDescriptionClick={() => { }}
|
onEditDescriptionClick={() => {}}
|
||||||
/>
|
/>
|
||||||
<div className="generate-report">
|
<div className="generate-report">
|
||||||
<button className="btn btn-primary">Generate Report</button>
|
<button className="btn btn-primary">Generate Report</button>
|
||||||
|
|||||||
@@ -3,6 +3,142 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.12.33](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.32...@ohif/extension-vtk@1.12.33) (2022-09-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.32](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.31...@ohif/extension-vtk@1.12.32) (2022-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.31](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.30...@ohif/extension-vtk@1.12.31) (2022-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.30](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.29...@ohif/extension-vtk@1.12.30) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.29](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.28...@ohif/extension-vtk@1.12.29) (2022-08-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.28](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.27...@ohif/extension-vtk@1.12.28) (2022-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.27](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.26...@ohif/extension-vtk@1.12.27) (2022-06-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.26](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.25...@ohif/extension-vtk@1.12.26) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.25](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.24...@ohif/extension-vtk@1.12.25) (2022-06-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.24](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.23...@ohif/extension-vtk@1.12.24) (2022-06-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.23](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.22...@ohif/extension-vtk@1.12.23) (2022-04-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.22](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.21...@ohif/extension-vtk@1.12.22) (2022-04-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.21](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.20...@ohif/extension-vtk@1.12.21) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.20](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.19...@ohif/extension-vtk@1.12.20) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.19](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.18...@ohif/extension-vtk@1.12.19) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.18](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.17...@ohif/extension-vtk@1.12.18) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.12.17](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.16...@ohif/extension-vtk@1.12.17) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.12.16](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.15...@ohif/extension-vtk@1.12.16) (2022-02-15)
|
## [1.12.16](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.12.15...@ohif/extension-vtk@1.12.16) (2022-02-15)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/extension-vtk
|
**Note:** Version bump only for package @ohif/extension-vtk
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/extension-vtk",
|
"name": "@ohif/extension-vtk",
|
||||||
"version": "1.12.16",
|
"version": "1.12.33",
|
||||||
"description": "OHIF extension for VTK.js",
|
"description": "OHIF extension for VTK.js",
|
||||||
"author": "OHIF",
|
"author": "OHIF",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"cornerstone-core": "^2.6.1",
|
"cornerstone-core": "^2.6.1",
|
||||||
"cornerstone-tools": "^6.0.6",
|
"cornerstone-tools": "^6.0.6",
|
||||||
"cornerstone-wado-image-loader": "^4.1.0",
|
"cornerstone-wado-image-loader": "^4.1.0",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"dicom-parser": "^1.8.11",
|
"dicom-parser": "^1.8.11",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
"i18next-browser-languagedetector": "^3.0.1",
|
"i18next-browser-languagedetector": "^3.0.1",
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
"react-vtkjs-viewport": "^0.14.4"
|
"react-vtkjs-viewport": "^0.14.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ohif/core": "^2.16.12",
|
"@ohif/core": "^2.16.28",
|
||||||
"@ohif/ui": "^1.10.6",
|
"@ohif/ui": "^1.10.10",
|
||||||
"cornerstone-tools": "^6.0.6",
|
"cornerstone-tools": "^6.0.6",
|
||||||
"cornerstone-wado-image-loader": "^4.1.0",
|
"cornerstone-wado-image-loader": "^4.1.0",
|
||||||
"dicom-parser": "^1.8.11",
|
"dicom-parser": "^1.8.11",
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
"shader-loader": "^1.3.1",
|
"shader-loader": "^1.3.1",
|
||||||
"start-server-and-test": "^1.10.0",
|
"start-server-and-test": "^1.10.0",
|
||||||
"style-loader": "^1.0.0",
|
"style-loader": "^1.0.0",
|
||||||
|
"styled-components": "^5.3.5",
|
||||||
"stylelint": "^10.1.0",
|
"stylelint": "^10.1.0",
|
||||||
"stylelint-config-recommended": "^2.2.0",
|
"stylelint-config-recommended": "^2.2.0",
|
||||||
"stylus": "^0.54.5",
|
"stylus": "^0.54.5",
|
||||||
|
|||||||
@@ -3,6 +3,140 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.16.28](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.27...@ohif/core@2.16.28) (2022-09-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.27](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.26...@ohif/core@2.16.27) (2022-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.26](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.25...@ohif/core@2.16.26) (2022-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.25](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.24...@ohif/core@2.16.25) (2022-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.24](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.23...@ohif/core@2.16.24) (2022-08-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.23](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.22...@ohif/core@2.16.23) (2022-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.22](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.21...@ohif/core@2.16.22) (2022-06-30)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.21](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.20...@ohif/core@2.16.21) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.20](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.19...@ohif/core@2.16.20) (2022-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Re IDC2797, fix double parsing of SR qualitative annotations ([#2830](https://github.com/OHIF/Viewers/issues/2830)) ([9f813e0](https://github.com/OHIF/Viewers/commit/9f813e0ea08f0aada8efab9ef6228ad90dd1758d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.19](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.18...@ohif/core@2.16.19) (2022-06-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.18](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.17...@ohif/core@2.16.18) (2022-04-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.17](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.16...@ohif/core@2.16.17) (2022-04-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.16](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.15...@ohif/core@2.16.16) (2022-04-05)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.15](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.14...@ohif/core@2.16.15) (2022-03-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.14](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.13...@ohif/core@2.16.14) (2022-03-14)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.16.13](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.12...@ohif/core@2.16.13) (2022-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Update fetchPaletteColorLookupTableData: LUT Entries shall be 0 if the table entries value is 2^16 ([#2395](https://github.com/OHIF/Viewers/issues/2395)) ([0ba796c](https://github.com/OHIF/Viewers/commit/0ba796c73c5254f1bc5ac72c58fd06abf19d7102))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.16.12](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.11...@ohif/core@2.16.12) (2022-02-15)
|
## [2.16.12](https://github.com/OHIF/Viewers/compare/@ohif/core@2.16.11...@ohif/core@2.16.12) (2022-02-15)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/core
|
**Note:** Version bump only for package @ohif/core
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/core",
|
"name": "@ohif/core",
|
||||||
"version": "2.16.12",
|
"version": "2.16.28",
|
||||||
"description": "Generic business logic for web-based medical imaging applications",
|
"description": "Generic business logic for web-based medical imaging applications",
|
||||||
"author": "OHIF Core Team",
|
"author": "OHIF Core Team",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"dcmjs": "0.19.4",
|
"dcmjs": "0.24.10",
|
||||||
"dicomweb-client": "^0.8.3",
|
"dicomweb-client": "^0.8.3",
|
||||||
"immer": "9.0.12",
|
"immer": "9.0.12",
|
||||||
"isomorphic-base64": "^1.0.2",
|
"isomorphic-base64": "^1.0.2",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
|
TEXT: 'TEXT',
|
||||||
POINT: 'POINT',
|
POINT: 'POINT',
|
||||||
MULTIPOINT: 'MULTIPOINT',
|
MULTIPOINT: 'MULTIPOINT',
|
||||||
POLYLINE: 'POLYLINE',
|
POLYLINE: 'POLYLINE',
|
||||||
|
|||||||
@@ -8,6 +8,16 @@ const parseSCOORD3D = ({ servicesManager, displaySets }) => {
|
|||||||
const { MeasurementService } = servicesManager.services;
|
const { MeasurementService } = servicesManager.services;
|
||||||
|
|
||||||
const srDisplaySets = displaySets.filter(ds => ds.Modality === 'SR');
|
const srDisplaySets = displaySets.filter(ds => ds.Modality === 'SR');
|
||||||
|
const imageDisplaySets = displaySets.filter(
|
||||||
|
ds =>
|
||||||
|
ds.Modality !== 'SR' &&
|
||||||
|
ds.Modality !== 'SEG' &&
|
||||||
|
ds.Modality !== 'RTSTRUCT'
|
||||||
|
);
|
||||||
|
|
||||||
|
imageDisplaySets.forEach(imageDisplaySet => {
|
||||||
|
imageDisplaySet.SRLabels = [];
|
||||||
|
});
|
||||||
|
|
||||||
srDisplaySets.forEach(srDisplaySet => {
|
srDisplaySets.forEach(srDisplaySet => {
|
||||||
const firstInstance = srDisplaySet.metadata;
|
const firstInstance = srDisplaySet.metadata;
|
||||||
@@ -18,7 +28,7 @@ const parseSCOORD3D = ({ servicesManager, displaySets }) => {
|
|||||||
const { ContentSequence } = firstInstance;
|
const { ContentSequence } = firstInstance;
|
||||||
|
|
||||||
srDisplaySet.referencedImages = getReferencedImagesList(ContentSequence);
|
srDisplaySet.referencedImages = getReferencedImagesList(ContentSequence);
|
||||||
srDisplaySet.measurements = getMeasurements(ContentSequence, srDisplaySet);
|
srDisplaySet.measurements = getMeasurements(ContentSequence);
|
||||||
const mappings = MeasurementService.getSourceMappings(
|
const mappings = MeasurementService.getSourceMappings(
|
||||||
'CornerstoneTools',
|
'CornerstoneTools',
|
||||||
'4'
|
'4'
|
||||||
@@ -28,13 +38,6 @@ const parseSCOORD3D = ({ servicesManager, displaySets }) => {
|
|||||||
srDisplaySet.isRehydratable = isRehydratable(srDisplaySet, mappings);
|
srDisplaySet.isRehydratable = isRehydratable(srDisplaySet, mappings);
|
||||||
srDisplaySet.isLoaded = true;
|
srDisplaySet.isLoaded = true;
|
||||||
|
|
||||||
const imageDisplaySets = displaySets.filter(
|
|
||||||
ds =>
|
|
||||||
ds.Modality !== 'SR' &&
|
|
||||||
ds.Modality !== 'SEG' &&
|
|
||||||
ds.Modality !== 'RTSTRUCT' &&
|
|
||||||
ds.Modality !== 'RTDOSE'
|
|
||||||
);
|
|
||||||
imageDisplaySets.forEach(imageDisplaySet => {
|
imageDisplaySets.forEach(imageDisplaySet => {
|
||||||
// Check currently added displaySets and add measurements if the sources exist.
|
// Check currently added displaySets and add measurements if the sources exist.
|
||||||
checkIfCanAddMeasurementsToDisplaySet(srDisplaySet, imageDisplaySet);
|
checkIfCanAddMeasurementsToDisplaySet(srDisplaySet, imageDisplaySet);
|
||||||
@@ -127,10 +130,10 @@ const checkIfCanAddMeasurementsToDisplaySet = (
|
|||||||
|
|
||||||
const imageIds = images.map(i => i.getImageId());
|
const imageIds = images.map(i => i.getImageId());
|
||||||
const SOPInstanceUIDs = images.map(i => i.SOPInstanceUID);
|
const SOPInstanceUIDs = images.map(i => i.SOPInstanceUID);
|
||||||
|
const colors = new Map();
|
||||||
measurements.forEach(measurement => {
|
measurements.forEach(measurement => {
|
||||||
const { coords } = measurement;
|
const { coords } = measurement;
|
||||||
|
coords.forEach((coord, index) => {
|
||||||
coords.forEach(coord => {
|
|
||||||
if (coord.ReferencedSOPSequence !== undefined) {
|
if (coord.ReferencedSOPSequence !== undefined) {
|
||||||
const imageIndex = SOPInstanceUIDs.findIndex(
|
const imageIndex = SOPInstanceUIDs.findIndex(
|
||||||
SOPInstanceUID =>
|
SOPInstanceUID =>
|
||||||
@@ -138,14 +141,50 @@ const checkIfCanAddMeasurementsToDisplaySet = (
|
|||||||
coord.ReferencedSOPSequence.ReferencedSOPInstanceUID
|
coord.ReferencedSOPSequence.ReferencedSOPInstanceUID
|
||||||
);
|
);
|
||||||
if (imageIndex > -1) {
|
if (imageIndex > -1) {
|
||||||
|
if (!srDisplaySet.referencedDisplaySets.includes(imageDisplaySet)) {
|
||||||
|
srDisplaySet.referencedDisplaySets.push(imageDisplaySet);
|
||||||
|
}
|
||||||
|
|
||||||
const imageId = imageIds[imageIndex];
|
const imageId = imageIds[imageIndex];
|
||||||
const imageMetadata = images[imageIndex].getData().metadata;
|
const imageMetadata = images[imageIndex].getData().metadata;
|
||||||
addMeasurement(
|
|
||||||
measurement,
|
if (coord.GraphicType === 'TEXT') {
|
||||||
imageId,
|
const key =
|
||||||
imageMetadata,
|
measurement.labels[index].label + measurement.labels[index].value;
|
||||||
imageDisplaySet.displaySetInstanceUID
|
let color = colors.get(key);
|
||||||
);
|
if (!color) {
|
||||||
|
// random dark color
|
||||||
|
color =
|
||||||
|
'hsla(' + Math.floor(Math.random() * 360) + ', 70%, 30%, 1)';
|
||||||
|
colors.set(key, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
measurement.labels[index].color = color;
|
||||||
|
measurement.isSRText = true;
|
||||||
|
measurement.labels[index].visible = true;
|
||||||
|
|
||||||
|
imageDisplaySet.SRLabels.push({
|
||||||
|
ReferencedSOPInstanceUID:
|
||||||
|
coord.ReferencedSOPSequence.ReferencedSOPInstanceUID,
|
||||||
|
labels: measurement.labels[index],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
addMeasurement(
|
||||||
|
measurement,
|
||||||
|
imageId,
|
||||||
|
imageMetadata,
|
||||||
|
imageDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addMeasurement(
|
||||||
|
measurement,
|
||||||
|
imageId,
|
||||||
|
imageMetadata,
|
||||||
|
imageDisplaySet.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ export default function addMeasurement(
|
|||||||
|
|
||||||
const measurementData = {
|
const measurementData = {
|
||||||
TrackingUniqueIdentifier: measurement.TrackingUniqueIdentifier,
|
TrackingUniqueIdentifier: measurement.TrackingUniqueIdentifier,
|
||||||
|
TrackingIdentifier: measurement.TrackingIdentifier,
|
||||||
renderableData: {},
|
renderableData: {},
|
||||||
labels: measurement.labels,
|
labels: measurement.labels,
|
||||||
|
isSRText: measurement.isSRText,
|
||||||
};
|
};
|
||||||
|
|
||||||
measurement.coords.forEach(coord => {
|
measurement.coords.forEach(coord => {
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
const getCoordsFromSCOORDOrSCOORD3D = (graphicItem, displaySet) => {
|
const getCoordsFromSCOORDOrSCOORD3D = graphicItem => {
|
||||||
const { ValueType, RelationshipType, GraphicType, GraphicData } = graphicItem;
|
const { ValueType, GraphicType, GraphicData } = graphicItem;
|
||||||
|
|
||||||
// if (RelationshipType !== RELATIONSHIP_TYPE.INFERRED_FROM) {
|
|
||||||
// console.warn(
|
|
||||||
// `Relationshiptype === ${RelationshipType}. Cannot deal with NON TID-1400 SCOORD group with RelationshipType !== "INFERRED FROM."`
|
|
||||||
// );
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const coords = { ValueType, GraphicType, GraphicData };
|
const coords = { ValueType, GraphicType, GraphicData };
|
||||||
|
|
||||||
// ContentSequence has length of 1 as RelationshipType === 'INFERRED FROM'
|
|
||||||
if (ValueType === 'SCOORD') {
|
if (ValueType === 'SCOORD') {
|
||||||
const { ReferencedSOPSequence } = graphicItem.ContentSequence;
|
const { ReferencedSOPSequence } = graphicItem.ContentSequence;
|
||||||
coords.ReferencedSOPSequence = ReferencedSOPSequence;
|
coords.ReferencedSOPSequence = ReferencedSOPSequence;
|
||||||
} else if (ValueType === 'SCOORD3D') {
|
} else if (ValueType === 'SCOORD3D') {
|
||||||
if (graphicItem.ReferencedFrameOfReferenceUID) {
|
if (graphicItem.ReferencedFrameOfReferenceUID) {
|
||||||
coords.ReferencedFrameOfReferenceSequence = graphicItem.ReferencedFrameOfReferenceUID;
|
coords.ReferencedFrameOfReferenceSequence =
|
||||||
|
graphicItem.ReferencedFrameOfReferenceUID;
|
||||||
} else if (graphicItem.ContentSequence) {
|
} else if (graphicItem.ContentSequence) {
|
||||||
const {
|
const {
|
||||||
ReferencedFrameOfReferenceSequence,
|
ReferencedFrameOfReferenceSequence,
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import getSequenceAsArray from './getSequenceAsArray';
|
|||||||
import getMergedContentSequencesByTrackingUniqueIdentifiers from './getMergedContentSequencesByTrackingUniqueIdentifiers';
|
import getMergedContentSequencesByTrackingUniqueIdentifiers from './getMergedContentSequencesByTrackingUniqueIdentifiers';
|
||||||
import processMeasurement from './processMeasurement';
|
import processMeasurement from './processMeasurement';
|
||||||
|
|
||||||
const getMeasurements = (
|
const getMeasurements = ImagingMeasurementReportContentSequence => {
|
||||||
ImagingMeasurementReportContentSequence,
|
|
||||||
displaySet
|
|
||||||
) => {
|
|
||||||
const ImagingMeasurements = ImagingMeasurementReportContentSequence.find(
|
const ImagingMeasurements = ImagingMeasurementReportContentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
@@ -21,25 +18,19 @@ const getMeasurements = (
|
|||||||
CodeNameCodeSequenceValues.MeasurementGroup
|
CodeNameCodeSequenceValues.MeasurementGroup
|
||||||
);
|
);
|
||||||
|
|
||||||
const mergedContentSequencesByTrackingUniqueIdentifiers = getMergedContentSequencesByTrackingUniqueIdentifiers(
|
/* const mergedContentSequencesByTrackingUniqueIdentifiers = getMergedContentSequencesByTrackingUniqueIdentifiers(
|
||||||
MeasurementGroups
|
MeasurementGroups
|
||||||
);
|
);*/
|
||||||
|
|
||||||
let measurements = [];
|
let measurements = [];
|
||||||
|
|
||||||
Object.keys(mergedContentSequencesByTrackingUniqueIdentifiers).forEach(
|
MeasurementGroups.forEach(MeasurementGroup => {
|
||||||
trackingUniqueIdentifier => {
|
const contentSequence = MeasurementGroup.ContentSequence;
|
||||||
const mergedContentSequence =
|
const measurement = processMeasurement(contentSequence);
|
||||||
mergedContentSequencesByTrackingUniqueIdentifiers[
|
if (measurement) {
|
||||||
trackingUniqueIdentifier
|
measurements.push(measurement);
|
||||||
];
|
|
||||||
|
|
||||||
const measurement = processMeasurement(mergedContentSequence, displaySet);
|
|
||||||
if (measurement) {
|
|
||||||
measurements.push(measurement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
return measurements;
|
return measurements;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ const getReferencedImagesList = ImagingMeasurementReportContentSequence => {
|
|||||||
const ImageLibrary = ImagingMeasurementReportContentSequence.find(
|
const ImageLibrary = ImagingMeasurementReportContentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.ImageLibrary
|
CodeNameCodeSequenceValues.ImageLibrary ||
|
||||||
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
|
CodeNameCodeSequenceValues.ImagingMeasurements
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!ImageLibrary.ContentSequence) {
|
if (!ImageLibrary || !ImageLibrary.ContentSequence) {
|
||||||
return referencedImages;
|
return referencedImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,9 +21,15 @@ const getReferencedImagesList = ImagingMeasurementReportContentSequence => {
|
|||||||
).find(
|
).find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.ImageLibraryGroup
|
CodeNameCodeSequenceValues.ImageLibraryGroup ||
|
||||||
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
|
CodeNameCodeSequenceValues.MeasurementGroup
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!ImageLibraryGroup || !ImageLibraryGroup.ContentSequence) {
|
||||||
|
return referencedImages;
|
||||||
|
}
|
||||||
|
|
||||||
getSequenceAsArray(ImageLibraryGroup.ContentSequence).forEach(item => {
|
getSequenceAsArray(ImageLibraryGroup.ContentSequence).forEach(item => {
|
||||||
const { ReferencedSOPSequence } = item;
|
const { ReferencedSOPSequence } = item;
|
||||||
if (ReferencedSOPSequence) {
|
if (ReferencedSOPSequence) {
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ const getRenderableData = (
|
|||||||
|
|
||||||
// https://dicom.innolitics.com/ciods/procedure-log/sr-document-content/00700023
|
// https://dicom.innolitics.com/ciods/procedure-log/sr-document-content/00700023
|
||||||
switch (GraphicType) {
|
switch (GraphicType) {
|
||||||
|
case SCOORD_TYPES.TEXT:
|
||||||
|
renderableData = [{ x: GraphicData[0], y: GraphicData[1] }];
|
||||||
|
|
||||||
|
break;
|
||||||
case SCOORD_TYPES.POINT:
|
case SCOORD_TYPES.POINT:
|
||||||
renderableData = [];
|
renderableData = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import processTID1410Measurement from './processTID1410Measurement';
|
import processTID1410Measurement from './processTID1410Measurement';
|
||||||
import processNonGeometricallyDefinedMeasurement from './processNonGeometricallyDefinedMeasurement';
|
import processNonGeometricallyDefinedMeasurement from './processNonGeometricallyDefinedMeasurement';
|
||||||
|
|
||||||
const processMeasurement = (mergedContentSequence, displaySet) => {
|
const processMeasurement = contentSequence => {
|
||||||
if (
|
if (
|
||||||
mergedContentSequence.some(
|
contentSequence.some(
|
||||||
group => group.ValueType === 'SCOORD' || group.ValueType === 'SCOORD3D'
|
group => group.ValueType === 'SCOORD' || group.ValueType === 'SCOORD3D'
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return processTID1410Measurement(mergedContentSequence, displaySet);
|
return processTID1410Measurement(contentSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
return processNonGeometricallyDefinedMeasurement(mergedContentSequence);
|
return processNonGeometricallyDefinedMeasurement(contentSequence);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default processMeasurement;
|
export default processMeasurement;
|
||||||
+46
-6
@@ -1,31 +1,40 @@
|
|||||||
import getLabelFromMeasuredValueSequence from './getLabelFromMeasuredValueSequence';
|
import getLabelFromMeasuredValueSequence from './getLabelFromMeasuredValueSequence';
|
||||||
import getCoordsFromSCOORDOrSCOORD3D from './getCoordsFromSCOORDOrSCOORD3D';
|
import getCoordsFromSCOORDOrSCOORD3D from './getCoordsFromSCOORDOrSCOORD3D';
|
||||||
import { CodeNameCodeSequenceValues, CodingSchemeDesignators } from '../enums';
|
import { CodeNameCodeSequenceValues, CodingSchemeDesignators } from '../enums';
|
||||||
|
import SCOORD_TYPES from '../constants/scoordTypes';
|
||||||
|
|
||||||
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
||||||
|
|
||||||
const processNonGeometricallyDefinedMeasurement = mergedContentSequence => {
|
const processNonGeometricallyDefinedMeasurement = contentSequence => {
|
||||||
const NUMContentItems = mergedContentSequence.filter(
|
const NUMContentItems = contentSequence.filter(
|
||||||
group => group.ValueType === 'NUM'
|
group => group.ValueType === 'NUM'
|
||||||
);
|
);
|
||||||
|
|
||||||
const UIDREFContentItem = mergedContentSequence.find(
|
const CODEContentItems = contentSequence.filter(
|
||||||
|
group => group.ValueType === 'CODE'
|
||||||
|
);
|
||||||
|
|
||||||
|
const UIDREFContentItem = contentSequence.find(
|
||||||
group => group.ValueType === 'UIDREF'
|
group => group.ValueType === 'UIDREF'
|
||||||
);
|
);
|
||||||
|
|
||||||
const TrackingIdentifierContentItem = mergedContentSequence.find(
|
const IMAGEContentItem = contentSequence.find(
|
||||||
|
group => group.ValueType === 'IMAGE'
|
||||||
|
);
|
||||||
|
|
||||||
|
const TrackingIdentifierContentItem = contentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.TrackingIdentifier
|
CodeNameCodeSequenceValues.TrackingIdentifier
|
||||||
);
|
);
|
||||||
|
|
||||||
const Finding = mergedContentSequence.find(
|
const Finding = contentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.Finding
|
CodeNameCodeSequenceValues.Finding
|
||||||
);
|
);
|
||||||
|
|
||||||
const FindingSites = mergedContentSequence.filter(
|
const FindingSites = contentSequence.filter(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodingSchemeDesignator ===
|
item.ConceptNameCodeSequence.CodingSchemeDesignator ===
|
||||||
CodingSchemeDesignators.SRT &&
|
CodingSchemeDesignators.SRT &&
|
||||||
@@ -111,6 +120,37 @@ const processNonGeometricallyDefinedMeasurement = mergedContentSequence => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (NUMContentItems.length === 0 && IMAGEContentItem) {
|
||||||
|
CODEContentItems.forEach(item => {
|
||||||
|
const { ConceptCodeSequence, ConceptNameCodeSequence } = item;
|
||||||
|
|
||||||
|
if (!ConceptCodeSequence || !ConceptNameCodeSequence) {
|
||||||
|
console.warn(`Graphic missing, skipping annotation.`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphicData = [0, 0];
|
||||||
|
const GraphicType = SCOORD_TYPES.TEXT;
|
||||||
|
const { ValueType } = item;
|
||||||
|
const ReferencedSOPSequence = IMAGEContentItem.ReferencedSOPSequence;
|
||||||
|
const coord = {
|
||||||
|
ValueType,
|
||||||
|
GraphicType,
|
||||||
|
GraphicData,
|
||||||
|
ReferencedSOPSequence,
|
||||||
|
};
|
||||||
|
measurement.coords.push(coord);
|
||||||
|
measurement.labels.push({
|
||||||
|
label: ConceptNameCodeSequence.CodeMeaning,
|
||||||
|
labelCodingSchemeDesignator:
|
||||||
|
ConceptNameCodeSequence.CodingSchemeDesignator,
|
||||||
|
value: ConceptCodeSequence.CodeMeaning,
|
||||||
|
valueCodingSchemeDesignator: ConceptCodeSequence.CodingSchemeDesignator,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return measurement;
|
return measurement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { RELATIONSHIP_TYPE, CodeNameCodeSequenceValues } from '../enums';
|
|||||||
/**
|
/**
|
||||||
* TID 1410 Planar ROI Measurements and Qualitative Evaluations.
|
* TID 1410 Planar ROI Measurements and Qualitative Evaluations.
|
||||||
*
|
*
|
||||||
* @param {*} mergedContentSequence
|
* @param {*} contentSequence
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const processTID1410Measurement = (mergedContentSequence, displaySet) => {
|
const processTID1410Measurement = contentSequence => {
|
||||||
// Need to deal with TID 1410 style measurements, which will have a SCOORD or SCOORD3D at the top level,
|
// Need to deal with TID 1410 style measurements, which will have a SCOORD or SCOORD3D at the top level,
|
||||||
// And non-geometric representations where each NUM has "INFERRED FROM" SCOORD/SCOORD3D
|
// And non-geometric representations where each NUM has "INFERRED FROM" SCOORD/SCOORD3D
|
||||||
|
|
||||||
const graphicItem = mergedContentSequence.find(
|
const graphicItem = contentSequence.find(
|
||||||
group => group.ValueType === 'SCOORD' || group.ValueType === 'SCOORD3D'
|
group => group.ValueType === 'SCOORD' || group.ValueType === 'SCOORD3D'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -23,24 +23,24 @@ const processTID1410Measurement = (mergedContentSequence, displaySet) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UIDREFContentItem = mergedContentSequence.find(
|
const UIDREFContentItem = contentSequence.find(
|
||||||
group => group.ValueType === 'UIDREF'
|
group => group.ValueType === 'UIDREF'
|
||||||
);
|
);
|
||||||
|
|
||||||
const TrackingIdentifierContentItem = mergedContentSequence.find(
|
const TrackingIdentifierContentItem = contentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.TrackingIdentifier
|
CodeNameCodeSequenceValues.TrackingIdentifier
|
||||||
);
|
);
|
||||||
|
|
||||||
const NUMContentItems = mergedContentSequence.filter(
|
const NUMContentItems = contentSequence.filter(
|
||||||
group => group.ValueType === 'NUM'
|
group => group.ValueType === 'NUM'
|
||||||
);
|
);
|
||||||
|
|
||||||
const measurement = {
|
const measurement = {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
labels: [],
|
labels: [],
|
||||||
coords: [getCoordsFromSCOORDOrSCOORD3D(graphicItem, displaySet)],
|
coords: [getCoordsFromSCOORDOrSCOORD3D(graphicItem)],
|
||||||
TrackingUniqueIdentifier: UIDREFContentItem.UID,
|
TrackingUniqueIdentifier: UIDREFContentItem.UID,
|
||||||
TrackingIdentifier: TrackingIdentifierContentItem.TextValue,
|
TrackingIdentifier: TrackingIdentifierContentItem.TextValue,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,16 +21,32 @@ const parseDicomStructuredReport = (
|
|||||||
displaySets,
|
displaySets,
|
||||||
external
|
external
|
||||||
) => {
|
) => {
|
||||||
if (external && external.servicesManager) {
|
|
||||||
parseSCOORD3D({ servicesManager: external.servicesManager, displaySets });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the dicom data as an Object
|
// Get the dicom data as an Object
|
||||||
const dicomData = dcmjs.data.DicomMessage.readFile(part10SRArrayBuffer);
|
const dicomData = dcmjs.data.DicomMessage.readFile(part10SRArrayBuffer);
|
||||||
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
|
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
|
||||||
dicomData.dict
|
dicomData.dict
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
LoggerService,
|
||||||
|
UINotificationService,
|
||||||
|
} = external.servicesManager.services;
|
||||||
|
if (external && external.servicesManager) {
|
||||||
|
try {
|
||||||
|
parseSCOORD3D({ servicesManager: external.servicesManager, displaySets });
|
||||||
|
} catch (error) {
|
||||||
|
const seriesDescription = dataset.SeriesDescription || '';
|
||||||
|
LoggerService.error({ error, message: error.message });
|
||||||
|
UINotificationService.show({
|
||||||
|
title: `Failed to parse ${seriesDescription} SR display set`,
|
||||||
|
message: error.message,
|
||||||
|
type: 'error',
|
||||||
|
autoClose: false,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { MeasurementReport } = dcmjs.adapters.Cornerstone;
|
const { MeasurementReport } = dcmjs.adapters.Cornerstone;
|
||||||
|
|
||||||
let storedMeasurementByToolType;
|
let storedMeasurementByToolType;
|
||||||
@@ -38,11 +54,12 @@ const parseDicomStructuredReport = (
|
|||||||
storedMeasurementByToolType = MeasurementReport.generateToolState(dataset);
|
storedMeasurementByToolType = MeasurementReport.generateToolState(dataset);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const seriesDescription = dataset.SeriesDescription || '';
|
const seriesDescription = dataset.SeriesDescription || '';
|
||||||
LogManager.publish(LogManager.EVENTS.OnLog, {
|
LoggerService.error({ error, message: error.message });
|
||||||
|
UINotificationService.show({
|
||||||
title: `Failed to parse ${seriesDescription} measurement report`,
|
title: `Failed to parse ${seriesDescription} measurement report`,
|
||||||
type: 'warning',
|
message: error.message,
|
||||||
message: error.message || '',
|
type: 'error',
|
||||||
notify: true,
|
autoClose: false,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,12 +67,13 @@ export class HotkeysManager {
|
|||||||
UINotificationService,
|
UINotificationService,
|
||||||
LoggerService,
|
LoggerService,
|
||||||
} = this._servicesManager.services;
|
} = this._servicesManager.services;
|
||||||
const message = 'Erro while setting hotkeys';
|
const message = 'Error while setting hotkeys';
|
||||||
LoggerService.error({ error, message });
|
LoggerService.error({ error, message });
|
||||||
UINotificationService.show({
|
UINotificationService.show({
|
||||||
title: 'Hotkeys Manager',
|
title: 'Hotkeys Manager',
|
||||||
message,
|
message,
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
autoClose: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ class StackLoadingListener extends BaseLoadingListener {
|
|||||||
const totalFramesCount = this.stack.imageIds.length;
|
const totalFramesCount = this.stack.imageIds.length;
|
||||||
const loadedFramesCount = this.loadedCount;
|
const loadedFramesCount = this.loadedCount;
|
||||||
const loadingFramesCount = totalFramesCount - loadedFramesCount;
|
const loadingFramesCount = totalFramesCount - loadedFramesCount;
|
||||||
const percentComplete = Math.round(
|
const percentComplete = Math.ceil(
|
||||||
(loadedFramesCount / totalFramesCount) * 100
|
(loadedFramesCount / totalFramesCount) * 100
|
||||||
);
|
);
|
||||||
const progressId = this._getProgressId();
|
const progressId = this._getProgressId();
|
||||||
@@ -469,8 +469,8 @@ class StudyLoadingListener {
|
|||||||
|
|
||||||
// TODO: Make this work for plugins
|
// TODO: Make this work for plugins
|
||||||
if (!stack) {
|
if (!stack) {
|
||||||
console.warn('Skipping adding displaySet to StudyLoadingListener');
|
//console.warn('Skipping adding displaySet to StudyLoadingListener');
|
||||||
console.warn(displaySet);
|
//console.warn(displaySet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import DICOMWeb from './../../DICOMWeb';
|
|||||||
import ImageSet from './../ImageSet';
|
import ImageSet from './../ImageSet';
|
||||||
import { InstanceMetadata } from './InstanceMetadata';
|
import { InstanceMetadata } from './InstanceMetadata';
|
||||||
import { Metadata } from './Metadata';
|
import { Metadata } from './Metadata';
|
||||||
import OHIFError from '../OHIFError';
|
|
||||||
import { SeriesMetadata } from './SeriesMetadata';
|
import { SeriesMetadata } from './SeriesMetadata';
|
||||||
// - createStacks
|
// - createStacks
|
||||||
import { api } from 'dicomweb-client';
|
import { api } from 'dicomweb-client';
|
||||||
// - createStacks
|
// - createStacks
|
||||||
import { isImage } from '../../utils/isImage';
|
import { isImage } from '../../utils/isImage';
|
||||||
|
import { naturalizeSOPClassUID } from '../../utils/naturalizeSOPClassUID';
|
||||||
import {
|
import {
|
||||||
isDisplaySetReconstructable,
|
isDisplaySetReconstructable,
|
||||||
isSpacingUniform,
|
isSpacingUniform,
|
||||||
@@ -169,8 +169,12 @@ class StudyMetadata extends Metadata {
|
|||||||
!isImage(instance.getTagValue('SOPClassUID')) &&
|
!isImage(instance.getTagValue('SOPClassUID')) &&
|
||||||
!instance.getTagValue('Rows')
|
!instance.getTagValue('Rows')
|
||||||
) {
|
) {
|
||||||
// we set an empty display and we add a isModalitySupported variable to
|
// we set an empty display and we add a isSOPClassUIDSupported variable to
|
||||||
// print a warning that the modality is not supported in the thumbnail.
|
// print a warning that the series is not supported in the thumbnail.
|
||||||
|
// SOPClassUIDNaturalized is human readable name, since for non image series,
|
||||||
|
// we could have a mismatch between the SOPClassUID and the Modality.
|
||||||
|
// For example, in the Parametric map IOD Modality is expected to match
|
||||||
|
// the value for the series used to generate Parametric map, and there is no "PM" modality.
|
||||||
const displaySet = new ImageSet([]);
|
const displaySet = new ImageSet([]);
|
||||||
const seriesData = series.getData();
|
const seriesData = series.getData();
|
||||||
displaySet.setAttributes({
|
displaySet.setAttributes({
|
||||||
@@ -188,7 +192,10 @@ class StudyMetadata extends Metadata {
|
|||||||
InstanceNumber: instance.getTagValue('InstanceNumber'), // Include the instance number
|
InstanceNumber: instance.getTagValue('InstanceNumber'), // Include the instance number
|
||||||
AcquisitionDatetime: instance.getTagValue('AcquisitionDateTime'), // Include the acquisition datetime
|
AcquisitionDatetime: instance.getTagValue('AcquisitionDateTime'), // Include the acquisition datetime
|
||||||
isReconstructable: false,
|
isReconstructable: false,
|
||||||
isModalitySupported: false,
|
isSOPClassUIDSupported: false,
|
||||||
|
SOPClassUIDNaturalized: naturalizeSOPClassUID(
|
||||||
|
instance.getTagValue('SOPClassUID')
|
||||||
|
),
|
||||||
metadata: instance.getData().metadata,
|
metadata: instance.getData().metadata,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -268,6 +275,8 @@ class StudyMetadata extends Metadata {
|
|||||||
|
|
||||||
const otherDisplaySets = allDisplaySets.filter(
|
const otherDisplaySets = allDisplaySets.filter(
|
||||||
ds =>
|
ds =>
|
||||||
|
ds &&
|
||||||
|
derivatedDisplaySet &&
|
||||||
ds.displaySetInstanceUID !== derivatedDisplaySet.displaySetInstanceUID
|
ds.displaySetInstanceUID !== derivatedDisplaySet.displaySetInstanceUID
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -333,10 +342,38 @@ class StudyMetadata extends Metadata {
|
|||||||
if (referencedSeriesInstanceUID) {
|
if (referencedSeriesInstanceUID) {
|
||||||
filteredDerivedDisplaySets = filteredDerivedDisplaySets.filter(
|
filteredDerivedDisplaySets = filteredDerivedDisplaySets.filter(
|
||||||
displaySet => {
|
displaySet => {
|
||||||
return (
|
const referencedDisplaySet = StudyMetadata.getReferencedDisplaySet(
|
||||||
StudyMetadata.getReferencedDisplaySet(displaySet, [this])
|
displaySet,
|
||||||
.SeriesInstanceUID === referencedSeriesInstanceUID
|
[this]
|
||||||
);
|
);
|
||||||
|
if (referencedDisplaySet) {
|
||||||
|
return (
|
||||||
|
referencedDisplaySet.SeriesInstanceUID ===
|
||||||
|
referencedSeriesInstanceUID
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
!displaySet.referencedDisplaySets ||
|
||||||
|
displaySet.referencedDisplaySets.length === 0
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredReferencedDisplaySets = displaySet.referencedDisplaySets.filter(
|
||||||
|
referencedDisplaySet =>
|
||||||
|
referencedDisplaySet.SeriesInstanceUID ===
|
||||||
|
referencedSeriesInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
filteredReferencedDisplaySets &&
|
||||||
|
filteredReferencedDisplaySets.length !== 0
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -923,7 +960,7 @@ const makeDisplaySet = (series, instances) => {
|
|||||||
: displayReconstructableInfo.reconstructionIssues;
|
: displayReconstructableInfo.reconstructionIssues;
|
||||||
}
|
}
|
||||||
|
|
||||||
imageSet.isModalitySupported = true;
|
imageSet.isSOPClassUIDSupported = true;
|
||||||
|
|
||||||
return imageSet;
|
return imageSet;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ export const dicomSRDisplayTool = {
|
|||||||
options: {
|
options: {
|
||||||
measurementTable: {
|
measurementTable: {
|
||||||
displayFunction: data => {
|
displayFunction: data => {
|
||||||
return `(SR) ${data.lesionNamingNumber ||
|
return `(SR) ${data.TrackingIdentifier ||
|
||||||
|
data.lesionNamingNumber ||
|
||||||
data.measurementNumber ||
|
data.measurementNumber ||
|
||||||
data.text ||
|
data.text ||
|
||||||
''}`;
|
''}`;
|
||||||
|
|||||||
@@ -420,6 +420,10 @@ class MeasurementService {
|
|||||||
throw new Error('No source definition provided.');
|
throw new Error('No source definition provided.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (definition == 'stack' || definition == 'stackPrefetch') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sourceInfo = this._getSourceInfo(source);
|
const sourceInfo = this._getSourceInfo(source);
|
||||||
|
|
||||||
if (!this._sourceHasMappings(source)) {
|
if (!this._sourceHasMappings(source)) {
|
||||||
|
|||||||
@@ -19,17 +19,4 @@ describe('retrieveStudyMetadata.js', () => {
|
|||||||
|
|
||||||
expect(callWithNoStudyInstanceUID).toThrow(Error);
|
expect(callWithNoStudyInstanceUID).toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('caches and returns the same promise for identical studyInstanceUIDs', () => {
|
|
||||||
const firstPromise = retrieveStudyMetadata(
|
|
||||||
fakeDicomWebServer,
|
|
||||||
'fake-study-instance-uid'
|
|
||||||
);
|
|
||||||
const secondPromise = retrieveStudyMetadata(
|
|
||||||
fakeDicomWebServer,
|
|
||||||
'fake-study-instance-uid'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(firstPromise).toBe(secondPromise);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
@@ -102,6 +102,35 @@ async function makeSOPInstance(server, study, instance) {
|
|||||||
SOPInstanceUID,
|
SOPInstanceUID,
|
||||||
} = naturalizedInstance;
|
} = naturalizedInstance;
|
||||||
|
|
||||||
|
const validate = string => {
|
||||||
|
let rgx = /[^.0-9]+/g;
|
||||||
|
return string.match(rgx);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (StudyInstanceUID === undefined || validate(StudyInstanceUID)) {
|
||||||
|
const error =
|
||||||
|
'makeSOPInstance: StudyInstanceUID is not conforming with the UID (DICOM UI VR) character repertoire, skipping SOPInstance.';
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SeriesInstanceUID === undefined || validate(SeriesInstanceUID)) {
|
||||||
|
const error =
|
||||||
|
'makeSOPInstance: SeriesInstanceUID is not conforming with the UID (DICOM UI VR) character repertoire, skipping SOPInstance.';
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SOPInstanceUID === undefined || validate(SOPInstanceUID)) {
|
||||||
|
const error =
|
||||||
|
'makeSOPInstance: SOPInstanceUID is not conforming with the UID (DICOM UI VR) character repertoire, skipping SOPInstance.';
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let series = study.seriesMap[SeriesInstanceUID];
|
let series = study.seriesMap[SeriesInstanceUID];
|
||||||
|
|
||||||
if (!series) {
|
if (!series) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function createAndAddStack(stackMap, study, displaySet, stackUpdatedCallbacks) {
|
|||||||
const imageIds = [];
|
const imageIds = [];
|
||||||
let imageId;
|
let imageId;
|
||||||
|
|
||||||
displaySet.images.forEach((instance, imageIndex) => {
|
images.forEach((instance, imageIndex) => {
|
||||||
const image = instance.getData();
|
const image = instance.getData();
|
||||||
const metaData = {
|
const metaData = {
|
||||||
instance: image, // in this context, instance will be the data of the InstanceMetadata object...
|
instance: image, // in this context, instance will be the data of the InstanceMetadata object...
|
||||||
@@ -35,7 +35,7 @@ function createAndAddStack(stackMap, study, displaySet, stackUpdatedCallbacks) {
|
|||||||
imageIndex: imageIndex + 1,
|
imageIndex: imageIndex + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const naturalizedInstance = instance.getData().metadata;
|
const naturalizedInstance = image.metadata;
|
||||||
const NumberOfFrames = naturalizedInstance.NumberOfFrames;
|
const NumberOfFrames = naturalizedInstance.NumberOfFrames;
|
||||||
|
|
||||||
if (NumberOfFrames > 1) {
|
if (NumberOfFrames > 1) {
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ import studyMetadataManager from './studyMetadataManager';
|
|||||||
* @param {object} snackbar
|
* @param {object} snackbar
|
||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
async function loadAndCacheDerivedDisplaySets(referencedDisplaySet, studies, logger, snackbar) {
|
async function loadAndCacheDerivedDisplaySets(
|
||||||
|
referencedDisplaySet,
|
||||||
|
studies,
|
||||||
|
logger,
|
||||||
|
snackbar
|
||||||
|
) {
|
||||||
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;
|
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;
|
||||||
const promises = [];
|
const promises = [];
|
||||||
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
|
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
|
||||||
@@ -80,60 +85,111 @@ async function loadAndCacheDerivedDisplaySets(referencedDisplaySet, studies, log
|
|||||||
});
|
});
|
||||||
|
|
||||||
// For each type, see if any are loaded, if not load the most recent.
|
// For each type, see if any are loaded, if not load the most recent.
|
||||||
await Promise.all(Object.keys(displaySetsPerModality).map(async (key) => {
|
await Promise.all(
|
||||||
const displaySets = displaySetsPerModality[key];
|
Object.keys(displaySetsPerModality).map(async key => {
|
||||||
|
const displaySets = displaySetsPerModality[key];
|
||||||
|
|
||||||
const isLoaded = displaySets.some(displaySet => displaySet.isLoaded);
|
const isLoaded = displaySets.some(displaySet => displaySet.isLoaded);
|
||||||
if (isLoaded) {
|
if (isLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (displaySets.some(displaySet => displaySet.loadError)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find most recent and load it.
|
|
||||||
let recentDateTime = 0;
|
|
||||||
let recentDisplaySet = displaySets[0];
|
|
||||||
|
|
||||||
displaySets.forEach(displaySet => {
|
|
||||||
const dateTime = Number(
|
|
||||||
`${displaySet.SeriesDate}${displaySet.SeriesTime}`
|
|
||||||
);
|
|
||||||
if (dateTime > recentDateTime) {
|
|
||||||
recentDateTime = dateTime;
|
|
||||||
recentDisplaySet = displaySet;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
if (displaySets.some(displaySet => displaySet.loadError)) {
|
||||||
if (recentDisplaySet.hasOwnProperty('getSourceDisplaySet') &&
|
return;
|
||||||
typeof recentDisplaySet.getSourceDisplaySet === 'function') {
|
|
||||||
await recentDisplaySet.getSourceDisplaySet(studies);
|
|
||||||
} else {
|
|
||||||
await recentDisplaySet.load(referencedDisplaySet, studies);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
recentDisplaySet.isLoaded = false;
|
// find most recent and load it.
|
||||||
recentDisplaySet.loadError = true;
|
let recentDateTime = 0;
|
||||||
logger.error({ error, message: error.message });
|
let recentDisplaySet = displaySets[0];
|
||||||
snackbar.show({
|
|
||||||
title: 'Error loading derived display set:',
|
displaySets.forEach(displaySet => {
|
||||||
message: error.message,
|
const dateTime = Number(
|
||||||
type: 'error',
|
`${displaySet.SeriesDate}${displaySet.SeriesTime}`
|
||||||
error,
|
);
|
||||||
autoClose: false,
|
if (dateTime > recentDateTime) {
|
||||||
|
recentDateTime = dateTime;
|
||||||
|
recentDisplaySet = displaySet;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}));
|
try {
|
||||||
|
if (
|
||||||
|
recentDisplaySet.hasOwnProperty('getSourceDisplaySet') &&
|
||||||
|
typeof recentDisplaySet.getSourceDisplaySet === 'function'
|
||||||
|
) {
|
||||||
|
if (recentDisplaySet.Modality === 'SEG' && logger) {
|
||||||
|
const onDisplaySetLoadFailureHandler = error => {
|
||||||
|
logger.error({ error, message: error.message });
|
||||||
|
snackbar.show({
|
||||||
|
title: 'DICOM Segmentation Loader',
|
||||||
|
message: error.message,
|
||||||
|
type: 'error',
|
||||||
|
autoClose: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let activatedLabelmapIndex = -1;
|
||||||
|
while (activatedLabelmapIndex == -1) {
|
||||||
|
const {
|
||||||
|
referencedDisplaySet,
|
||||||
|
activatedLabelmapPromise,
|
||||||
|
} = await recentDisplaySet.getSourceDisplaySet(
|
||||||
|
studies,
|
||||||
|
true,
|
||||||
|
onDisplaySetLoadFailureHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
activatedLabelmapIndex = await activatedLabelmapPromise;
|
||||||
|
const selectionFired = new CustomEvent(
|
||||||
|
'extensiondicomsegmentationsegselected',
|
||||||
|
{
|
||||||
|
detail: { activatedLabelmapIndex: activatedLabelmapIndex },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
document.dispatchEvent(selectionFired);
|
||||||
|
|
||||||
|
const lastDateTime = Number(
|
||||||
|
`${recentDisplaySet.SeriesDate}${recentDisplaySet.SeriesTime}`
|
||||||
|
);
|
||||||
|
recentDateTime = 0;
|
||||||
|
displaySets.forEach(displaySet => {
|
||||||
|
const dateTime = Number(
|
||||||
|
`${displaySet.SeriesDate}${displaySet.SeriesTime}`
|
||||||
|
);
|
||||||
|
if (dateTime > recentDateTime && dateTime < lastDateTime) {
|
||||||
|
recentDateTime = dateTime;
|
||||||
|
recentDisplaySet = displaySet;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await recentDisplaySet.getSourceDisplaySet(studies);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await recentDisplaySet.load(referencedDisplaySet, studies);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
recentDisplaySet.isLoaded = false;
|
||||||
|
recentDisplaySet.loadError = true;
|
||||||
|
logger.error({ error, message: error.message });
|
||||||
|
snackbar.show({
|
||||||
|
title: 'Error loading derived display set:',
|
||||||
|
message: error.message,
|
||||||
|
type: 'error',
|
||||||
|
error,
|
||||||
|
autoClose: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Improve the way we notify parts of the app
|
* TODO: Improve the way we notify parts of the app
|
||||||
* that depends on derived display sets to be loaded.
|
* that depends on derived display sets to be loaded.
|
||||||
* (Implement pubsub for better tracking of derived display sets)
|
* (Implement pubsub for better tracking of derived display sets)
|
||||||
*/
|
*/
|
||||||
const event = new CustomEvent('deriveddisplaysetsloadedandcached');
|
const event = new CustomEvent('deriveddisplaysetsloadedandcached');
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default loadAndCacheDerivedDisplaySets;
|
export default loadAndCacheDerivedDisplaySets;
|
||||||
@@ -113,7 +113,7 @@ const _paletteColorCache = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function _getPaletteColor(server, paletteColorLookupTableData, lutDescriptor) {
|
function _getPaletteColor(server, paletteColorLookupTableData, lutDescriptor) {
|
||||||
const numLutEntries = lutDescriptor[0];
|
const numLutEntries = lutDescriptor[0] ? lutDescriptor[0] : 65536;
|
||||||
const bits = lutDescriptor[2];
|
const bits = lutDescriptor[2];
|
||||||
|
|
||||||
const arrayBufferToPaletteColorLUT = arraybuffer => {
|
const arrayBufferToPaletteColorLUT = arraybuffer => {
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
import { sopClassDictionary } from './sopClassDictionary';
|
||||||
|
import { isImage } from './isImage';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Naturalize SOP Class UID which do not have image data
|
||||||
|
* @param {string} SOPClassUID - SOP Class UID to be converted
|
||||||
|
* @returns {string} - human readable name
|
||||||
|
*/
|
||||||
|
export const naturalizeSOPClassUID = SOPClassUID => {
|
||||||
|
let naturalizedName = '';
|
||||||
|
if (!SOPClassUID) return naturalizedName;
|
||||||
|
if (!isImage) return naturalizedName;
|
||||||
|
|
||||||
|
if (sopClassDictionary.MRSpectroscopyStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'MRSpectroscopy';
|
||||||
|
} else if (sopClassDictionary.EnhancedUSVolumeStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'EnhancedUSVolume';
|
||||||
|
} else if (sopClassDictionary.Sop12LeadECGWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'Sop12LeadECGWaveform';
|
||||||
|
} else if (sopClassDictionary.GeneralECGWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'GeneralECGWaveform';
|
||||||
|
} else if (sopClassDictionary.AmbulatoryECGWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'AECAmbulatoryECGWaveformGW';
|
||||||
|
} else if (sopClassDictionary.HemodynamicWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'HemodynamicWaveform';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.CardiacElectrophysiologyWaveformStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'CardiacElectrophysiologyWaveform';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.BasicVoiceAudioWaveformStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'BasicVoiceAudioWaveform';
|
||||||
|
} else if (sopClassDictionary.GeneralAudioWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'GGeneralAudioWaveformAW';
|
||||||
|
} else if (sopClassDictionary.ArterialPulseWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'APArterialPulseWaveformW';
|
||||||
|
} else if (sopClassDictionary.RespiratoryWaveformStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RespiratoryWaveform';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.GrayscaleSoftcopyPresentationStateStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'GrayscaleSoftcopyPresentationState';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.ColorSoftcopyPresentationStateStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'ColorSoftcopyPresentationState';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.PseudoColorSoftcopyPresentationStateStorage ===
|
||||||
|
SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'PseudoColorSoftcopyPresentationState';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.BlendingSoftcopyPresentationStateStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'BlendingSoftcopyPresentationState';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.XAXRFGrayscaleSoftcopyPresentationStateStorage ===
|
||||||
|
SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'XAXRFGrayscaleSoftcopyPresentationState';
|
||||||
|
} else if (sopClassDictionary.RawDataStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RawData';
|
||||||
|
} else if (sopClassDictionary.SpatialRegistrationStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SpatialRegistration';
|
||||||
|
} else if (sopClassDictionary.SpatialFiducialsStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SpatialFiducials';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.DeformableSpatialRegistrationStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'DeformableSpatialRegistration';
|
||||||
|
} else if (sopClassDictionary.SegmentationStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SEG';
|
||||||
|
} else if (sopClassDictionary.SurfaceSegmentationStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SurfaceSEG';
|
||||||
|
} else if (sopClassDictionary.RealWorldValueMappingStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RealWorldValueMapping';
|
||||||
|
} else if (sopClassDictionary.SurfaceScanMeshStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SurfaceScanMesh';
|
||||||
|
} else if (sopClassDictionary.SurfaceScanPointCloudStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'SurfaceScanPointCloud';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.StereometricRelationshipStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'StereometricRelationship';
|
||||||
|
} else if (sopClassDictionary.LensometryMeasurementsStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'LensometryMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.AutorefractionMeasurementsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'AutorefractionMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.KeratometryMeasurementsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'KeratometryMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.SubjectiveRefractionMeasurementsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'SubjectiveRefractionMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.VisualAcuityMeasurementsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'VisualAcuityMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.SpectaclePrescriptionReportStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'SpectaclePrescriptionReport';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.OphthalmicAxialMeasurementsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'OphthalmicAxialMeasurements';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.IntraocularLensCalculationsStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'IntraocularLensCalculations';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.MacularGridThicknessandVolumeReport === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'MacularGridThicknessandVolume';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.OphthalmicVisualFieldStaticPerimetryMeasurementsStorage ===
|
||||||
|
SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'OphthalmicVisualFieldStaticPerimetryMeasurements';
|
||||||
|
} else if (sopClassDictionary.OphthalmicThicknessMapStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'OphthalmicThicknessMap';
|
||||||
|
} else if (sopClassDictionary.CornealTopographyMapStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'CornealTopographyMap';
|
||||||
|
} else if (sopClassDictionary.BasicTextSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'BasicTextSR';
|
||||||
|
} else if (sopClassDictionary.EnhancedSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'EnhancedSR';
|
||||||
|
} else if (sopClassDictionary.ComprehensiveSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'ComprehensiveSR';
|
||||||
|
} else if (sopClassDictionary.Comprehensive3DSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'Comprehensive3DSR';
|
||||||
|
} else if (sopClassDictionary.ProcedureLog === SOPClassUID) {
|
||||||
|
naturalizedName = 'ProcedureLog';
|
||||||
|
} else if (sopClassDictionary.MammographyCADSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'MammographyCADSR';
|
||||||
|
} else if (sopClassDictionary.KeyObjectSelection === SOPClassUID) {
|
||||||
|
naturalizedName = 'KeyObject';
|
||||||
|
} else if (sopClassDictionary.ChestCADSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'ChestCADSR';
|
||||||
|
} else if (sopClassDictionary.XRayRadiationDoseSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'XRayRadiationDoseSR';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.RadiopharmaceuticalRadiationDoseSR === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'RadiopharmaceuticalRadiationDoseSR';
|
||||||
|
} else if (sopClassDictionary.ColonCADSR === SOPClassUID) {
|
||||||
|
naturalizedName = 'ColonCADSR';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.ImplantationPlanSRDocumentStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'ImplantationPlanSRDocument';
|
||||||
|
} else if (sopClassDictionary.EncapsulatedPDFStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'EncapsulatedPDF';
|
||||||
|
} else if (sopClassDictionary.EncapsulatedCDAStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'EncapsulatedCDA';
|
||||||
|
} else if (sopClassDictionary.BasicStructuredDisplayStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'BasicStructuredDisplay';
|
||||||
|
} else if (sopClassDictionary.RTDoseStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RTDose';
|
||||||
|
} else if (sopClassDictionary.RTStructureSetStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RTStructureSet';
|
||||||
|
} else if (sopClassDictionary.RTBeamsTreatmentRecordStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RTBeamsTreatmentRecord';
|
||||||
|
} else if (sopClassDictionary.RTPlanStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RTPlan';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.RTBrachyTreatmentRecordStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'RTBrachyTreatmentRecord';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.RTTreatmentSummaryRecordStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'RTTreatmentSummaryRecord';
|
||||||
|
} else if (sopClassDictionary.RTIonPlanStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'RTIonPlan';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.RTIonBeamsTreatmentRecordStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'RTIonBeamsTreatmentRecord';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.RTBeamsDeliveryInstructionStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'RTBeamsDeliveryInstruction';
|
||||||
|
} else if (sopClassDictionary.GenericImplantTemplateStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'GenericImplantTemplate';
|
||||||
|
} else if (
|
||||||
|
sopClassDictionary.ImplantAssemblyTemplateStorage === SOPClassUID
|
||||||
|
) {
|
||||||
|
naturalizedName = 'ImplantAssemblyTemplate';
|
||||||
|
} else if (sopClassDictionary.ImplantTemplateGroupStorage === SOPClassUID) {
|
||||||
|
naturalizedName = 'ImplantTemplateGroup';
|
||||||
|
}
|
||||||
|
|
||||||
|
return naturalizedName;
|
||||||
|
};
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
####
|
####
|
||||||
##
|
##
|
||||||
## We need to pin WebPack's version for docz to work. See this issue:
|
|
||||||
## https://github.com/pedronauck/docz/issues/704#issuecomment-480295032
|
|
||||||
##
|
|
||||||
## react-scripts checks that dependency versions match before running
|
## react-scripts checks that dependency versions match before running
|
||||||
## Our top level webpack version causes the preflight check to fail
|
## Our top level webpack version causes the preflight check to fail
|
||||||
## This prevents that check
|
## This prevents that check
|
||||||
|
|||||||
@@ -3,6 +3,41 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.10.10](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.9...@ohif/ui@1.10.10) (2022-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.10.9](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.8...@ohif/ui@1.10.9) (2022-06-29)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.10.8](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.7...@ohif/ui@1.10.8) (2022-04-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.10.7](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.6...@ohif/ui@1.10.7) (2022-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* remove docz + node version fix on docker ([#2743](https://github.com/OHIF/Viewers/issues/2743)) ([7164d1a](https://github.com/OHIF/Viewers/commit/7164d1a654571af99c22d2684e56cbdde05b2222))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.10.6](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.5...@ohif/ui@1.10.6) (2022-02-03)
|
## [1.10.6](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.10.5...@ohif/ui@1.10.6) (2022-02-03)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ohif/ui
|
**Note:** Version bump only for package @ohif/ui
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* Docz Configuration File:
|
|
||||||
* https://www.docz.site/docs/project-configuration
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { css } from "docz-plugin-css";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
dest: "example/build",
|
|
||||||
public: "/public",
|
|
||||||
wrapper: "src/__docs__/wrapper",
|
|
||||||
indexHtml: "src/__docs__/index.html",
|
|
||||||
// Limited support for importing `.styl` files
|
|
||||||
codeSandbox: false,
|
|
||||||
// https://github.com/pedronauck/docz/pull/849/files
|
|
||||||
// Because we re-export using `index.js` files
|
|
||||||
notUseSpecifiers: true,
|
|
||||||
menu: [
|
|
||||||
"Introduction",
|
|
||||||
"Getting Started",
|
|
||||||
{ name: "Elements", menu: ["Form / Select"] },
|
|
||||||
{
|
|
||||||
name: "Components",
|
|
||||||
menu: [
|
|
||||||
"CINE Dialog",
|
|
||||||
"Layout Button",
|
|
||||||
"Measurement Table",
|
|
||||||
"Overlay Trigger",
|
|
||||||
"Quick Switch",
|
|
||||||
"Rounded Button Group",
|
|
||||||
"Select Tree",
|
|
||||||
"Simple Dialog",
|
|
||||||
"Study Browser",
|
|
||||||
"Study List",
|
|
||||||
"Table List",
|
|
||||||
"Toolbar Section",
|
|
||||||
"About Modal",
|
|
||||||
"User Preferences Modal"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Styling & Theming",
|
|
||||||
"Translating",
|
|
||||||
"Compatibility"
|
|
||||||
],
|
|
||||||
// Rollup Aliases?
|
|
||||||
// https://github.com/pedronauck/docz/issues/373
|
|
||||||
plugins: [
|
|
||||||
// CSS
|
|
||||||
css(),
|
|
||||||
// Stylus
|
|
||||||
css({
|
|
||||||
preprocessor: "stylus",
|
|
||||||
cssmodules: false
|
|
||||||
})
|
|
||||||
],
|
|
||||||
// `docz` uses file-loader to pull in SVGs. This kills our icons before
|
|
||||||
// They can be picked up by our `babel-plugin-inline-react-svg` dependency
|
|
||||||
// You can see where it's configured here:
|
|
||||||
// https://github.com/pedronauck/docz/blob/f72624d0aa5231dab17e1770e8d36be920f590a2/core/docz-core/src/bundler/loaders.ts#L135-L144
|
|
||||||
// How we delete our rule:
|
|
||||||
// https://github.com/neutrinojs/webpack-chain/issues/48
|
|
||||||
onCreateWebpackChain: config => {
|
|
||||||
config.module.rules.delete("svg");
|
|
||||||
},
|
|
||||||
modifyBabelRc: babelrc => {
|
|
||||||
const newBabelRc = {
|
|
||||||
...babelrc,
|
|
||||||
plugins: [
|
|
||||||
...babelrc.plugins,
|
|
||||||
require.resolve("babel-plugin-inline-react-svg")
|
|
||||||
]
|
|
||||||
};
|
|
||||||
return newBabelRc;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
// ~~ Plugins
|
|
||||||
const PnpWebpackPlugin = require(`pnp-webpack-plugin`); // Required until Webpack@5
|
|
||||||
|
|
||||||
exports.onCreateWebpackConfig = args => {
|
|
||||||
args.actions.setWebpackConfig({
|
|
||||||
node: { fs: 'empty' },
|
|
||||||
resolve: {
|
|
||||||
plugins: [PnpWebpackPlugin],
|
|
||||||
// Note the '..' in the path because docz gatsby project lives in the '.docz' directory
|
|
||||||
modules: [
|
|
||||||
// platform/ui
|
|
||||||
path.resolve(__dirname, '../node_modules'),
|
|
||||||
// .docz
|
|
||||||
'node_modules',
|
|
||||||
],
|
|
||||||
// resolve: {
|
|
||||||
// symlinks: true,
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
resolveLoader: {
|
|
||||||
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ohif/ui",
|
"name": "@ohif/ui",
|
||||||
"version": "1.10.6",
|
"version": "1.10.10",
|
||||||
"description": "A set of React components for Medical Imaging Viewers",
|
"description": "A set of React components for Medical Imaging Viewers",
|
||||||
"author": "OHIF Contributors",
|
"author": "OHIF Contributors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -20,9 +20,8 @@
|
|||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "docz dev",
|
"dev": "echo \"No dev script yet\" && exit 0",
|
||||||
"dev:ui": "yarn run dev",
|
"dev:ui": "yarn run dev",
|
||||||
"docs": "docz build",
|
|
||||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||||
"build:package": "yarn run build",
|
"build:package": "yarn run build",
|
||||||
"prepublishOnly": "yarn run build",
|
"prepublishOnly": "yarn run build",
|
||||||
@@ -64,10 +63,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdx-js/tag": "^0.20.3",
|
"@mdx-js/tag": "^0.20.3",
|
||||||
"autoprefixer": "^9.6.0",
|
"autoprefixer": "^9.6.0",
|
||||||
"docz": "1.2.0",
|
|
||||||
"docz-core": "1.2.0",
|
|
||||||
"docz-plugin-css": "0.11.0",
|
|
||||||
"docz-theme-default": "1.2.0",
|
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"react-powerplug": "1.0.0"
|
"react-powerplug": "1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import React, { Fragment } from 'react';
|
|
||||||
import { Link } from 'docz';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const NameSpace = ({ name }) => (
|
|
||||||
<Fragment>
|
|
||||||
The namespace used on this component was: <pre>{name}</pre> Check the{' '}
|
|
||||||
<Link to="/translating#how-to-translate-components">translation docs</Link>{' '}
|
|
||||||
to see how to override it.
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
NameSpace.propTypes = {
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NameSpace;
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
@@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
name: Compatibility
|
|
||||||
route: /compatibility
|
|
||||||
---
|
|
||||||
|
|
||||||
# Compatibility
|
|
||||||
|
|
||||||
## Browser Support
|
|
||||||
|
|
||||||
`@ohif/ui` relies on
|
|
||||||
[browsers supported by Styled Components](https://www.styled-components.com/docs/faqs#which-browsers-are-supported)
|
|
||||||
or browsers supported by emotion.
|
|
||||||
|
|
||||||
Supported Browsers: IE11, IE 9+ (with Map + Set polyfills), Chrome, Firefox (and
|
|
||||||
derivatives), Edge, and Safari.
|
|
||||||
Whitespace-only changes.
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
name: Docs Settings
|
|
||||||
route: /docs-settings
|
|
||||||
---
|
|
||||||
|
|
||||||
import LanguageSwitcher from '../components/languageSwitcher';
|
|
||||||
|
|
||||||
# Components Language
|
|
||||||
|
|
||||||
You can change the language of the components displayed in this documentation by
|
|
||||||
choosing an option in the selector below:
|
|
||||||
|
|
||||||
<LanguageSwitcher />
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
---
|
|
||||||
name: Getting Started
|
|
||||||
route: /getting-started
|
|
||||||
---
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
> This component library is pre- v1.0. All realeases until a v1.0 have the
|
|
||||||
> possibility of introducing breaking changes. Please depend on an "exact"
|
|
||||||
> version in your projects to prevent issues caused by loose versioning.
|
|
||||||
|
|
||||||
Install `@ohif/ui` from npm:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
// with npm
|
|
||||||
npm i @ohif/ui --save-exact
|
|
||||||
|
|
||||||
// with yarn
|
|
||||||
yarn add @ohif/ui --exact
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
There is some setup required for `@ohif/ui`. We are working to eliminate these
|
|
||||||
requirements with the goal of providing ready to use components.
|
|
||||||
|
|
||||||
### External Dependencies
|
|
||||||
|
|
||||||
We have tried to keep the number of external dependencies limited to make setup
|
|
||||||
as easy as possible. You will, however, need to include either the default font
|
|
||||||
or the font you set for your theme:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Google Fonts, Roboto
|
|
||||||
'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700&display=swap';
|
|
||||||
```
|
|
||||||
|
|
||||||
`@ohif/ui` also looks for theme CSS variabled defined on `:root`. You can find a
|
|
||||||
list of variables [on the theming page](/styling-and-theming)
|
|
||||||
|
|
||||||
### Import & Use
|
|
||||||
|
|
||||||
You can use components in your React app:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { LayoutButton } from '@ohif/ui';
|
|
||||||
|
|
||||||
class Example extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
selectedCell: {
|
|
||||||
className: 'hover',
|
|
||||||
col: 1,
|
|
||||||
row: 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<LayoutButton
|
|
||||||
selectedCell={this.state.selectedCell}
|
|
||||||
onChange={cell => this.setState({ selectedCell: cell })}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> NOTE: It is heavily recommended that you use a CSS reset or normalize. As well
|
|
||||||
> as the following style: `* { Box-sizing: Border-box }`
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="{{ lang }}">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="description" content="{{ description }}">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
|
|
||||||
<title>{{ title }}</title>
|
|
||||||
|
|
||||||
<!-- Latest compiled and minified CSS -->
|
|
||||||
<link rel="stylesheet" href="/public/docz.css">
|
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700&display=swap">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* "Tide" theme */
|
|
||||||
/* TODO:
|
|
||||||
- Convert the other themes to CSS Variables
|
|
||||||
- Allow user to set default CSS theme in JS config
|
|
||||||
- Export the themes as identical JS objects
|
|
||||||
- For theme switcher, update root-level CSS properties via JS (https://medium.com/@_bengarrison/accessing-and-modifying-css-variables-with-javascript-2ccb735bbff0)
|
|
||||||
*/
|
|
||||||
:root {
|
|
||||||
/* Interface UI Colors */
|
|
||||||
--default-color: #9CCEF9;
|
|
||||||
--hover-color: #ffffff;
|
|
||||||
--active-color: #20A5D6;
|
|
||||||
--ui-border-color: #44626F;
|
|
||||||
--ui-border-color-dark: #3C5D80;
|
|
||||||
--ui-border-color-active: #00a4d9;
|
|
||||||
--primary-background-color: #000000;
|
|
||||||
--box-background-color: #3E5975;
|
|
||||||
|
|
||||||
--text-primary-color: #ffffff;
|
|
||||||
--text-secondary-color: #91B9CD;
|
|
||||||
--input-background-color: #2c363f;
|
|
||||||
--input-placeholder-color: #d3d3d3;
|
|
||||||
|
|
||||||
--table-hover-color: #2c363f;
|
|
||||||
--table-text-primary-color: #ffffff;
|
|
||||||
--table-text-secondary-color: #91b9cd;
|
|
||||||
|
|
||||||
--large-numbers-color: #6FBDE2;
|
|
||||||
|
|
||||||
--state-error: #FFCCCC;
|
|
||||||
--state-error-border: #FFCCCC;
|
|
||||||
--state-error-text: #FFCCCC;
|
|
||||||
|
|
||||||
/* Common palette */
|
|
||||||
--ui-yellow: #E29E4A;
|
|
||||||
--ui-sky-blue: #6FBDE2;
|
|
||||||
/* State palette */
|
|
||||||
--ui-state-error: #FFCCCC;
|
|
||||||
--ui-state-error-border: #993333;
|
|
||||||
--ui-state-error-text: #661111;
|
|
||||||
--ui-gray-lighter: #436270;
|
|
||||||
--ui-gray-light: #516873;
|
|
||||||
--ui-gray: #263340;
|
|
||||||
--ui-gray-dark: #16202B;
|
|
||||||
--ui-gray-darker: #151A1F;
|
|
||||||
--ui-gray-darkest: #14202A;
|
|
||||||
|
|
||||||
--calendar-day-color: #d3d3d3;
|
|
||||||
--calendar-day-border-color: #d3d3d3;
|
|
||||||
--calendar-day-active-hover-background-color: #516873;
|
|
||||||
--calendar-main-color: #263340;
|
|
||||||
--viewport-border-thickness: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Roboto', sans-serif !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{ head }}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="root" />
|
|
||||||
{{ footer }}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
---
|
|
||||||
name: Introduction
|
|
||||||
route: /
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz';
|
|
||||||
import { State } from 'react-powerplug';
|
|
||||||
import { TableList, TableListItem } from './../index.js';
|
|
||||||
|
|
||||||
# Introduction
|
|
||||||
|
|
||||||
**@ohif/ui is a collection of components and utilities** that power OHIF's
|
|
||||||
[zero-footprint DICOM viewer](https://github.com/OHIF/Viewers)
|
|
||||||
([demo][demo-url]). We maintain them as a separate component library to:
|
|
||||||
|
|
||||||
- Decouple presentation from business logic
|
|
||||||
- Test and develop components in isolation
|
|
||||||
- Provide well documented, reusable components
|
|
||||||
- Aid rapid application development for context specific viewers
|
|
||||||
|
|
||||||
## Quick Example
|
|
||||||
|
|
||||||
> This component library is pre- v1.0. All realeases until a v1.0 have the
|
|
||||||
> possibility of introducing breaking changes. Please depend on an "exact"
|
|
||||||
> version in your projects to prevent issues caused by loose versioning.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Add '@ohif/ui' as a dependency
|
|
||||||
yarn add @ohif/ui
|
|
||||||
|
|
||||||
// Import and use components
|
|
||||||
import { TableList } from '@ohif/ui'
|
|
||||||
```
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
selectedIndex: null,
|
|
||||||
listItems: [
|
|
||||||
{ label: 'Brain Left' },
|
|
||||||
{ label: 'Brain Right' },
|
|
||||||
{ label: 'Heart Left' },
|
|
||||||
{ label: 'Heart Right' },
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<TableList headerTitle="Example Table List Header">
|
|
||||||
{state.listItems.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<TableListItem
|
|
||||||
key={`item_${index}`}
|
|
||||||
itemClass={state.selectedIndex === index ? 'selected' : ''}
|
|
||||||
itemIndex={index}
|
|
||||||
onItemClick={() => alert('item clicked')}
|
|
||||||
>
|
|
||||||
<label>{item.label}</label>
|
|
||||||
</TableListItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableList>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Links
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- prettier-ignore-start -->
|
|
||||||
[demo-url]: https://docs.ohif.org/demo/
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
name: Styling & Theming
|
|
||||||
route: /styling-and-theming
|
|
||||||
---
|
|
||||||
|
|
||||||
# Styling & Theming
|
|
||||||
|
|
||||||
```css
|
|
||||||
:root {
|
|
||||||
/* Interface UI Colors */
|
|
||||||
--default-color: #9ccef9;
|
|
||||||
--hover-color: #ffffff;
|
|
||||||
--active-color: #20a5d6;
|
|
||||||
--ui-border-color: #44626f;
|
|
||||||
--ui-border-color-dark: #3c5d80;
|
|
||||||
--ui-border-color-active: #00a4d9;
|
|
||||||
--primary-background-color: #000000;
|
|
||||||
--box-background-color: #3e5975;
|
|
||||||
|
|
||||||
--text-primary-color: #ffffff;
|
|
||||||
--text-secondary-color: #91b9cd;
|
|
||||||
--input-background-color: #2c363f;
|
|
||||||
--input-placeholder-color: #d3d3d3;
|
|
||||||
|
|
||||||
--table-hover-color: #2c363f;
|
|
||||||
--table-text-primary-color: #ffffff;
|
|
||||||
--table-text-secondary-color: #91b9cd;
|
|
||||||
|
|
||||||
--large-numbers-color: #6fbde2;
|
|
||||||
|
|
||||||
--state-error: #ffcccc;
|
|
||||||
--state-error-border: #ffcccc;
|
|
||||||
--state-error-text: #ffcccc;
|
|
||||||
|
|
||||||
/* Common palette */
|
|
||||||
--ui-yellow: #e29e4a;
|
|
||||||
--ui-sky-blue: #6fbde2;
|
|
||||||
|
|
||||||
/* State palette */
|
|
||||||
--ui-state-error: #ffcccc;
|
|
||||||
--ui-state-error-border: #993333;
|
|
||||||
--ui-state-error-text: #661111;
|
|
||||||
--ui-gray-lighter: #436270;
|
|
||||||
--ui-gray-light: #516873;
|
|
||||||
--ui-gray: #263340;
|
|
||||||
--ui-gray-dark: #16202b;
|
|
||||||
--ui-gray-darker: #151a1f;
|
|
||||||
--ui-gray-darkest: #14202a;
|
|
||||||
|
|
||||||
--calendar-day-color: #d3d3d3;
|
|
||||||
--calendar-day-border-color: #d3d3d3;
|
|
||||||
--calendar-day-active-hover-background-color: #516873;
|
|
||||||
--calendar-main-color: #263340;
|
|
||||||
--viewport-border-thickness: 1px;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
---
|
|
||||||
name: Translating
|
|
||||||
route: /translating
|
|
||||||
---
|
|
||||||
|
|
||||||
# Translating
|
|
||||||
|
|
||||||
**React Viewerbase** supports internationalization using
|
|
||||||
[i18next](https://www.i18next.com/) through the npm package
|
|
||||||
[@ohif/i18n](https://www.npmjs.com/package/@ohif/i18n), where is the main
|
|
||||||
instance of i18n containing several languages and tools.
|
|
||||||
|
|
||||||
## How to translate components
|
|
||||||
|
|
||||||
All you need is to use the internal custom superset of
|
|
||||||
[withTranslation HOC](https://react.i18next.com/latest/withtranslation-hoc),
|
|
||||||
available at `src/utils/LanguageProvider.js`
|
|
||||||
|
|
||||||
e.g.:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React from 'react';
|
|
||||||
import { withTranslation } from '../utils/LanguageProvider.js';
|
|
||||||
|
|
||||||
function MyComponent({ t }) {
|
|
||||||
return <p>{t('my translated text')}</p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withTranslation('MyNameSpace')(MyComponent);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Namespaces
|
|
||||||
|
|
||||||
For further information about namespaces and how they work, please visit
|
|
||||||
[OHIF Namespaces docs](https://docs.ohif.org/viewer/internationalization.html#namespaces).
|
|
||||||
|
|
||||||
### How to get right the Namespace of a `@ohif/ui` component?
|
|
||||||
|
|
||||||
Check the component's page in this site, the Namespace information should be on
|
|
||||||
the bottom line.
|
|
||||||
|
|
||||||
Also, a nameSpace is defined when exporting a component, this information can be
|
|
||||||
found on exports trough the code, in case of missing in docs.
|
|
||||||
|
|
||||||
E.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
export default withTranslation('TheNamespaceYouAreLookingFor')(TheComponentYouWantToUse);
|
|
||||||
```
|
|
||||||
|
|
||||||
### How to use another Namespace inside the current Namespace?
|
|
||||||
|
|
||||||
i18next provides a parsing feature able to get translations strings from any
|
|
||||||
Namespace, like this following example getting data from `InnerSpace` Namespace:
|
|
||||||
|
|
||||||
```
|
|
||||||
$t(InnerSpace:Reset)
|
|
||||||
export default withTranslation('OuterSpace')(TheComponent);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## I18next Provider
|
|
||||||
|
|
||||||
**@ohif/ui** pass down the `t` function trough the custom
|
|
||||||
[withTranslation HOC](https://github.com/OHIF/Viewers/blob/master/platform/ui/src/utils/LanguageProvider.js).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Extending and Overriding languages
|
|
||||||
|
|
||||||
[How to Extend languages with @ohif/i18n](https://docs.ohif.org/viewer/internationalization.html#extending-languages-in-ohifi18n)
|
|
||||||
|
|
||||||
## Changing the language
|
|
||||||
|
|
||||||
The language choosing method is the same implemented in
|
|
||||||
[OHIF Viewers](https://docs.ohif.org/viewer/internationalization.html#changing-the-language)
|
|
||||||
|
|
||||||
> You can also change the language of the components displayed in this
|
|
||||||
> documentation by choosing an option in the
|
|
||||||
> [Docs Settings](https://react.ohif.org/docs-settings) section.
|
|
||||||
|
|
||||||
## Debugging translations
|
|
||||||
|
|
||||||
[How to Debug @ohif/i18n](https://docs.ohif.org/viewer/internationalization.html#debugging-translations)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import LanguageSwitcher from '../components/languageSwitcher';
|
|
||||||
|
|
||||||
import './wrapper.styl';
|
|
||||||
|
|
||||||
const Wrapper = ({ children }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div className="sidebarLanguageSwitcher">
|
|
||||||
<strong>Display components in:</strong>
|
|
||||||
<LanguageSwitcher />
|
|
||||||
</div>
|
|
||||||
{children}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
Wrapper.propTypes = {
|
|
||||||
children: PropTypes.node.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Wrapper;
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
[class*="Sidebar__Menus"]
|
|
||||||
@media (min-width: 1120px)
|
|
||||||
margin-top: 80px
|
|
||||||
|
|
||||||
.sidebarLanguageSwitcher
|
|
||||||
position: fixed
|
|
||||||
top: 155px
|
|
||||||
left 0
|
|
||||||
z-index: 1049
|
|
||||||
padding: 0 24px 20px
|
|
||||||
border-bottom: 1px dotted #CED4DE
|
|
||||||
background: #F5F6F7
|
|
||||||
transition: all 200ms ease
|
|
||||||
@media (max-width: 1119px)
|
|
||||||
left -100%
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
name: Checkbox
|
|
||||||
menu: Elements
|
|
||||||
route: /components/checkbox
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { Checkbox } from './../index'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
# Checkbox
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
checked : false,
|
|
||||||
label : 'Sample check'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
||||||
<Checkbox {...state} />
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={Checkbox} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="Checkbox" />
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
name: CINE Dialog
|
|
||||||
menu: Components
|
|
||||||
route: /components/cine-dialog
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { CineDialog } from './../index'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
# CINE Dialog
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
isPlaying: false,
|
|
||||||
cineFrameRate: 24,
|
|
||||||
isLoopEnabled: true,
|
|
||||||
lastChange: '',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
||||||
<CineDialog
|
|
||||||
{...state}
|
|
||||||
onClickSkipToStart={() =>
|
|
||||||
setState({ lastChange: 'Clicked SkipToStart' })
|
|
||||||
}
|
|
||||||
onClickSkipToEnd={() =>
|
|
||||||
setState({ lastChange: 'Clicked SkipToEnd' })
|
|
||||||
}
|
|
||||||
onClickNextButton={() => setState({ lastChange: 'Clicked Next' })}
|
|
||||||
onClickBackButton={() => setState({ lastChange: 'Clicked Back' })}
|
|
||||||
onLoopChanged={value => setState({ isLoopEnabled: value })}
|
|
||||||
onFrameRateChanged={value => setState({ cineFrameRate: value })}
|
|
||||||
onPlayPauseChanged={() => setState({ isPlaying: !state.isPlaying })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={CineDialog} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="CineDialog" />
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
name: About Modal
|
|
||||||
menu: Components
|
|
||||||
route: /components/about-modal
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { AboutContent } from './../index.js'
|
|
||||||
|
|
||||||
# About Modal
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State initial={{
|
|
||||||
isOpen: false
|
|
||||||
}}>
|
|
||||||
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
type="button"
|
|
||||||
onClick={ () => setState({ isOpen: true }) }
|
|
||||||
>
|
|
||||||
Open about modal
|
|
||||||
</button>
|
|
||||||
<AboutContent
|
|
||||||
{...state}
|
|
||||||
onCancel={() => setState({ isOpen: false })}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</State>
|
|
||||||
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={AboutContent} />
|
|
||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
name: Viewport Download Form
|
|
||||||
menu: Components
|
|
||||||
route: /components/viewport-download-form
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { ViewportDownloadForm } from './../index'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
# Viewport Download Form
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<div style={{ maxWidth: '400px', margin: '0 auto' }}>
|
|
||||||
<ViewportDownloadForm />
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={ViewportDownloadForm} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="ViewportDownloadForm" />
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
.LayoutExample {
|
|
||||||
background-color: var(--primary-background-color);
|
|
||||||
width: 160px;
|
|
||||||
height: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.GridLayout td {
|
|
||||||
padding: 5px;
|
|
||||||
border: 1px solid black;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
---
|
|
||||||
name: Layout Button
|
|
||||||
menu: Components
|
|
||||||
route: /components/layout-button
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { LayoutButton } from './../index.js'
|
|
||||||
import './layoutButton.css'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
# Layout Button
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State initial={{
|
|
||||||
selectedCell: {
|
|
||||||
className: 'hover',
|
|
||||||
col: 1,
|
|
||||||
row: 1
|
|
||||||
},
|
|
||||||
}}>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
{/* STATE */}
|
|
||||||
<div><pre>{JSON.stringify(state, null, 2) }</pre></div>
|
|
||||||
|
|
||||||
{/* COMPONENT */}
|
|
||||||
<div className="LayoutExample">
|
|
||||||
<LayoutButton
|
|
||||||
{...state}
|
|
||||||
onChange={cell => setState({ selectedCell: cell })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={LayoutButton} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="Buttons" />
|
|
||||||
@@ -9,6 +9,14 @@ import { TableListItem } from './../tableList/TableListItem.js';
|
|||||||
|
|
||||||
import './MeasurementTableItem.styl';
|
import './MeasurementTableItem.styl';
|
||||||
|
|
||||||
|
const ColoredCircle = ({ color }) => {
|
||||||
|
return <div className="item-color" style={{ backgroundColor: color }}></div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColoredCircle.propTypes = {
|
||||||
|
color: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
class MeasurementTableItem extends Component {
|
class MeasurementTableItem extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
measurementData: PropTypes.object.isRequired,
|
measurementData: PropTypes.object.isRequired,
|
||||||
@@ -21,6 +29,14 @@ class MeasurementTableItem extends Component {
|
|||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
collapsed: true,
|
||||||
|
visible: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
warningTitle = '',
|
warningTitle = '',
|
||||||
@@ -93,27 +109,115 @@ class MeasurementTableItem extends Component {
|
|||||||
actionButtons.push(deleteButton);
|
actionButtons.push(deleteButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
if (
|
||||||
<TableListItem
|
this.props.measurementData.isSRText === true &&
|
||||||
itemKey={this.props.measurementData.measurementNumber}
|
this.props.measurementData.labels &&
|
||||||
itemClass={`measurementItem ${this.props.itemClass} ${hasWarningClass}`}
|
this.props.measurementData.labels.length > 0
|
||||||
itemIndex={this.props.itemIndex}
|
) {
|
||||||
onItemClick={this.onItemClick}
|
return (
|
||||||
>
|
<React.Fragment>
|
||||||
<div>
|
<TableListItem
|
||||||
<div className="measurementLocation">
|
key={this.props.measurementData.measurementNumber}
|
||||||
{this.props.t(this.props.measurementData.label, {
|
itemKey={this.props.measurementData.measurementNumber}
|
||||||
keySeparator: '>',
|
itemClass={`measurementItem ${this.props.itemClass} ${hasWarningClass}`}
|
||||||
nsSeparator: '|',
|
itemIndex={this.props.itemIndex}
|
||||||
|
onItemClick={this.onItemClick}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="measurementLocation">
|
||||||
|
{this.props.t(this.props.measurementData.label, {
|
||||||
|
keySeparator: '>',
|
||||||
|
nsSeparator: '|',
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="icons">
|
||||||
|
<div className="displayTexts">{this.getDataDisplayText()}</div>
|
||||||
|
<Icon
|
||||||
|
className={`eye-icon`}
|
||||||
|
name={this.state.visible ? 'eye' : 'eye-closed'}
|
||||||
|
width="20px"
|
||||||
|
height="20px"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.measurementData.labels.forEach(label => {
|
||||||
|
label.visible = !this.state.visible;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
visible: !this.state.visible,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
className={`angle-double-${
|
||||||
|
this.state.collapsed ? 'down' : 'up'
|
||||||
|
}`}
|
||||||
|
name={`angle-double-${this.state.collapsed ? 'down' : 'up'}`}
|
||||||
|
width="20px"
|
||||||
|
height="20px"
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({
|
||||||
|
collapsed: !this.state.collapsed,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TableListItem>
|
||||||
|
{this.state.collapsed &&
|
||||||
|
this.props.measurementData.labels.map((SRLabel, index) => {
|
||||||
|
return (
|
||||||
|
<TableListItem
|
||||||
|
key={index}
|
||||||
|
itemKey={index}
|
||||||
|
itemMeta={<ColoredCircle color={SRLabel.color} />}
|
||||||
|
itemMetaClass="item-color-section"
|
||||||
|
onItemClick={this.onItemClick}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="icons">
|
||||||
|
<span style={{ width: '90px' }}>
|
||||||
|
{SRLabel.label + ' : ' + SRLabel.value}
|
||||||
|
</span>
|
||||||
|
<Icon
|
||||||
|
className={`eye-icon`}
|
||||||
|
name={SRLabel.visible ? 'eye' : 'eye-closed'}
|
||||||
|
width="20px"
|
||||||
|
height="20px"
|
||||||
|
onClick={() => {
|
||||||
|
SRLabel.visible = !SRLabel.visible;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TableListItem>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<TableListItem
|
||||||
|
key={this.props.measurementData.measurementNumber}
|
||||||
|
itemKey={this.props.measurementData.measurementNumber}
|
||||||
|
itemClass={`measurementItem ${this.props.itemClass} ${hasWarningClass}`}
|
||||||
|
itemIndex={this.props.itemIndex}
|
||||||
|
onItemClick={this.onItemClick}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="measurementLocation">
|
||||||
|
{this.props.t(this.props.measurementData.label, {
|
||||||
|
keySeparator: '>',
|
||||||
|
nsSeparator: '|',
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="displayTexts">{this.getDataDisplayText()}</div>
|
||||||
|
{!this.props.measurementData.isReadOnly && (
|
||||||
|
<div className="rowActions">{actionButtons}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="displayTexts">{this.getDataDisplayText()}</div>
|
</TableListItem>
|
||||||
{!this.props.measurementData.isReadOnly && (
|
);
|
||||||
<div className="rowActions">{actionButtons}</div>
|
}
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</TableListItem>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onItemClick = event => {
|
onItemClick = event => {
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
.measurementItem
|
.measurementItem
|
||||||
|
.item-color-section
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.item-color
|
||||||
|
margin-top: 8px;
|
||||||
|
border-radius: 100%;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
.rowActions
|
.rowActions
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
background-color: var(--ui-gray-darker)
|
background-color: var(--ui-gray-darker)
|
||||||
@@ -63,3 +75,16 @@
|
|||||||
width: 22px;
|
width: 22px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
pointer-events: inherit;
|
pointer-events: inherit;
|
||||||
|
|
||||||
|
.icons
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
.icons .eye-icon
|
||||||
|
margin-left: 100px;
|
||||||
|
margin-right: -5px;
|
||||||
|
.icons .angle-double-down
|
||||||
|
.icons .angle-double-up
|
||||||
|
margin-left: 15px;
|
||||||
|
margin-right: -5px;
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
---
|
|
||||||
name: Measurement Table
|
|
||||||
menu: Components
|
|
||||||
route: /components/measurement-table
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { MeasurementTable } from './../index.js'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
//
|
|
||||||
import measurements from './measurements.js'
|
|
||||||
import timepoints from './timepoints.js'
|
|
||||||
import warnings from './warnings.js'
|
|
||||||
|
|
||||||
# Measurement Table
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
// Spelling error: overwallWarnings
|
|
||||||
overwallWarnings: warnings,
|
|
||||||
timepoints,
|
|
||||||
measurementCollection: measurements,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<div style={{ height: '340px' }}>
|
|
||||||
<MeasurementTable
|
|
||||||
{...state}
|
|
||||||
onItemClick={() => alert('onItemClick')}
|
|
||||||
onRelabelClick={() => alert('onRelabelClick')}
|
|
||||||
onDeleteClick={() => alert('onDeleteClick')}
|
|
||||||
onEditDescriptionClick={() => alert('onEditDescriptionClick')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={MeasurementTable} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="MeasurementTable" />
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
maxMeasurements: 5,
|
|
||||||
groupName: 'Targets',
|
|
||||||
measurements: [
|
|
||||||
{
|
|
||||||
measurementId: '123',
|
|
||||||
measurementNumber: '123',
|
|
||||||
itemNumber: 1,
|
|
||||||
label: 'Chest Wall Posterior',
|
|
||||||
hasWarnings: true,
|
|
||||||
warningTitle: 'Criteria nonconformities',
|
|
||||||
isSplitLesion: false,
|
|
||||||
warningList: [
|
|
||||||
'All measurements should have a location',
|
|
||||||
'Nodal lesions must be >= 15mm short axis AND >= double the acquisition slice thickness by CT and MR',
|
|
||||||
],
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
displayText: '25.7 x 12.9',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: '24.7 x 11.5',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
measurementId: '124',
|
|
||||||
measurementNumber: '124',
|
|
||||||
itemNumber: 2,
|
|
||||||
label: 'Bone Extremity',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
displayText: '24.7 x 11.1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: '21.2 x 10.9',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
maxMeasurements: 3,
|
|
||||||
groupName: 'NonTargets',
|
|
||||||
measurements: [
|
|
||||||
{
|
|
||||||
measurementId: '125',
|
|
||||||
measurementNumber: '125',
|
|
||||||
itemNumber: 1,
|
|
||||||
label: 'Chest Wall Single Site',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
displayText: 'MD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: 'NM',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
measurementId: '126',
|
|
||||||
measurementNumber: '126',
|
|
||||||
itemNumber: 2,
|
|
||||||
label: 'Extremity Multiple Sites',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
displayText: 'CR',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
measurementId: '127',
|
|
||||||
measurementNumber: '127',
|
|
||||||
label: 'Extremity Site',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
displayText: 'CR',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
displayText: 'NM',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
label: 'Follow-up 2',
|
|
||||||
date: '20-Dec-18',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Follow-up 1',
|
|
||||||
date: '15-Jun-18',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Baseline',
|
|
||||||
date: '10-Apr-18',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export default {
|
|
||||||
warningList: [
|
|
||||||
'All measurements should have a location',
|
|
||||||
'Nodal lesions must be >= 15mm short axis AND >= double the acquisition slice thickness by CT and MR',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
name: OHIFModal
|
|
||||||
menu: Components
|
|
||||||
route: /components/ohif-modal
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { OHIFModal } from './../index'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
# OHIF Modal
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<div style={{ maxWidth: '400px', margin: '0 auto' }}>
|
|
||||||
<OHIFModal />
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={OHIFModal} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="OHIFModal" />
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
---
|
|
||||||
name: Overlay Trigger
|
|
||||||
menu: Components
|
|
||||||
route: /components/overlay-trigger
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { Tooltip } from './../../tooltip'
|
|
||||||
import { OverlayTrigger } from './../index.js'
|
|
||||||
|
|
||||||
# Overlay Trigger
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
### On Hover
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between'
|
|
||||||
}}>
|
|
||||||
{
|
|
||||||
['right', 'left', 'bottom', 'top'].map((placement) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={`example-${placement}`}>
|
|
||||||
<OverlayTrigger
|
|
||||||
key={`example-${placement}`}
|
|
||||||
placement={placement}
|
|
||||||
overlay={
|
|
||||||
<Tooltip
|
|
||||||
placement={placement}
|
|
||||||
className='in'
|
|
||||||
id={`tooltip-${placement}`}
|
|
||||||
>
|
|
||||||
Here I am!
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<button> Tooltip on {placement}</button>
|
|
||||||
</OverlayTrigger>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
### On Click
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{['right', 'left', 'bottom', 'top'].map(placement => {
|
|
||||||
return (
|
|
||||||
<OverlayTrigger
|
|
||||||
key={`example-${placement}`}
|
|
||||||
placement={placement}
|
|
||||||
trigger="click"
|
|
||||||
overlay={
|
|
||||||
<Tooltip
|
|
||||||
placement={placement}
|
|
||||||
className="in"
|
|
||||||
id={`tooltip-${placement}`}
|
|
||||||
>
|
|
||||||
Here I am!
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<button> Tooltip on {placement}</button>
|
|
||||||
</OverlayTrigger>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={OverlayTrigger} />
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
---
|
|
||||||
name: Quick Switch
|
|
||||||
menu: Components
|
|
||||||
route: /components/quick-switch
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { QuickSwitch } from './../index.js'
|
|
||||||
//
|
|
||||||
import studies from './studies.js'
|
|
||||||
|
|
||||||
# Quick Switch
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State initial={{
|
|
||||||
studyListData: studies,
|
|
||||||
}}>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<QuickSwitch
|
|
||||||
studyListData={state.studyListData}
|
|
||||||
// If this is always activeStudy's thumbnails,
|
|
||||||
// Why do we need to specify this?
|
|
||||||
seriesData={
|
|
||||||
state.studyListData.find((study) => {
|
|
||||||
return !!study.active;
|
|
||||||
}).thumbnails}
|
|
||||||
onSeriesSelected={(selectedSeries) => {
|
|
||||||
const { studyListData } = state;
|
|
||||||
const selectedId = selectedSeries.displaySetInstanceUID;
|
|
||||||
|
|
||||||
studyListData.forEach(study => {
|
|
||||||
study.thumbnails.forEach(series => {
|
|
||||||
series.active = series.displaySetInstanceUID === selectedId;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
setState({ studyListData });
|
|
||||||
}}
|
|
||||||
onStudySelected={(selectedStudy) => {
|
|
||||||
const { studyListData } = state;
|
|
||||||
const selectedId = selectedStudy.StudyInstanceUID;
|
|
||||||
|
|
||||||
studyListData.forEach(study => {
|
|
||||||
study.active = study.StudyInstanceUID === selectedId;
|
|
||||||
});
|
|
||||||
|
|
||||||
setState({ studyListData });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</State>
|
|
||||||
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={QuickSwitch} />
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
StudyInstanceUID: '10001',
|
|
||||||
StudyDescription: 'Anti-PD-1',
|
|
||||||
modalities: 'CT',
|
|
||||||
StudyDate: '18-nov-2018',
|
|
||||||
active: false,
|
|
||||||
thumbnails: [
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_Lung.jpg',
|
|
||||||
SeriesDescription: 'Anti-PD-1_Lung',
|
|
||||||
SeriesNumber: '2',
|
|
||||||
numImageFrames: 512,
|
|
||||||
displaySetInstanceUID: '10001-1',
|
|
||||||
stackPercentComplete: 30,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/Anti-PD-1_MELANOMA.jpg',
|
|
||||||
SeriesDescription: 'Anti-PD-1_MELANOMA',
|
|
||||||
SeriesNumber: '2',
|
|
||||||
InstanceNumber: '1',
|
|
||||||
numImageFrames: 256,
|
|
||||||
displaySetInstanceUID: '10001-2',
|
|
||||||
stackPercentComplete: 70,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
StudyInstanceUID: '10002',
|
|
||||||
StudyDescription: 'CPTAC',
|
|
||||||
modalities: 'CT',
|
|
||||||
StudyDate: '16-aug-2017',
|
|
||||||
active: true,
|
|
||||||
thumbnails: [
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-GBM.jpg',
|
|
||||||
SeriesDescription: 'CPTAC-GBM',
|
|
||||||
active: true,
|
|
||||||
SeriesNumber: '2',
|
|
||||||
numImageFrames: 512,
|
|
||||||
displaySetInstanceUID: '10002-1',
|
|
||||||
stackPercentComplete: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-CM.jpg',
|
|
||||||
SeriesDescription: 'CPTAC-CM',
|
|
||||||
SeriesNumber: '2',
|
|
||||||
InstanceNumber: '1',
|
|
||||||
displaySetInstanceUID: '10002-2',
|
|
||||||
numImageFrames: 256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-HNSCC.jpg',
|
|
||||||
SeriesDescription: 'CPTAC-HNSCC',
|
|
||||||
SeriesNumber: '2',
|
|
||||||
InstanceNumber: '1',
|
|
||||||
displaySetInstanceUID: '10002-3',
|
|
||||||
numImageFrames: 256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc:
|
|
||||||
'https://raw.githubusercontent.com/crowds-cure/cancer/master/public/screenshots/CPTAC-LSCC.jpg',
|
|
||||||
SeriesDescription: 'CPTAC-LSCC',
|
|
||||||
SeriesNumber: '2',
|
|
||||||
InstanceNumber: '1',
|
|
||||||
displaySetInstanceUID: '10002-4',
|
|
||||||
numImageFrames: 256,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
---
|
|
||||||
name: Radio Button List
|
|
||||||
menu: Elements
|
|
||||||
route: /components/radio-button-list
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { RadioButtonList } from './../index'
|
|
||||||
import NameSpace from '../../../__docs__/NameSpace'
|
|
||||||
|
|
||||||
#Radio Button List
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
description : [
|
|
||||||
{
|
|
||||||
'label' : 'Button 1',
|
|
||||||
'id' : 'button1',
|
|
||||||
'checked' : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'label' : 'Button 2',
|
|
||||||
'id' : 'button2',
|
|
||||||
'checked' : false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'label' : 'Button 3',
|
|
||||||
'id' : 'button3',
|
|
||||||
'checked' : true,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
||||||
<RadioButtonList description={[
|
|
||||||
{
|
|
||||||
'label' : 'Button 1',
|
|
||||||
'id' : 'button1',
|
|
||||||
'checked' : false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'label' : 'Button 2',
|
|
||||||
'id' : 'button2',
|
|
||||||
'checked' : false,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'label' : 'Button 3',
|
|
||||||
'id' : 'coolButton3',
|
|
||||||
'checked' : true,
|
|
||||||
}
|
|
||||||
]}/>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={RadioButtonList} />
|
|
||||||
|
|
||||||
## Translation Namespace
|
|
||||||
|
|
||||||
<NameSpace name="RadioButtonList" />
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
---
|
|
||||||
name: Rounded Button Group
|
|
||||||
menu: Components
|
|
||||||
route: /components/rounded-button-group
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz';
|
|
||||||
import { State } from 'react-powerplug';
|
|
||||||
import { RoundedButtonGroup } from './../index.js';
|
|
||||||
|
|
||||||
# Rounded Button Group
|
|
||||||
|
|
||||||
A basic styled toggle switch
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State
|
|
||||||
initial={{
|
|
||||||
value: null,
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: 'studies',
|
|
||||||
icon: 'th',
|
|
||||||
bottomLabel: 'Series',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'measurements',
|
|
||||||
icon: 'th-list',
|
|
||||||
bottomLabel: 'Measurements',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<div>
|
|
||||||
<pre>value: {JSON.stringify(state.value, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
<RoundedButtonGroup
|
|
||||||
{...state}
|
|
||||||
onValueChanged={value => setState({ value })}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</State>
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={RoundedButtonGroup} />
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
name: Select Tree
|
|
||||||
menu: Components
|
|
||||||
route: /components/select-tree
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Playground, Props } from 'docz'
|
|
||||||
import { State } from 'react-powerplug'
|
|
||||||
import { SelectTree } from './../index.js'
|
|
||||||
|
|
||||||
import selectTreeItems from './selectTreeItems.js'
|
|
||||||
|
|
||||||
# SelectTree
|
|
||||||
|
|
||||||
## Basic usage
|
|
||||||
|
|
||||||
<Playground>
|
|
||||||
<State initial={{
|
|
||||||
items: selectTreeItems,
|
|
||||||
}}>
|
|
||||||
{({ state, setState }) => (
|
|
||||||
<React.Fragment>
|
|
||||||
<pre style={{ maxHeight: '135px', overflowX: 'auto' }}>
|
|
||||||
{JSON.stringify(state.items, null, 2)}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<SelectTree
|
|
||||||
items={state.items}
|
|
||||||
onSelected={(event, item) => setState({ itemLabelSelected: item.label }) }
|
|
||||||
selectTreeFirstTitle="Select Tree Example Header"
|
|
||||||
autoFocus={false}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</State>
|
|
||||||
|
|
||||||
</Playground>
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
<Props of={SelectTree} />
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
label: 'A',
|
|
||||||
value: 'A',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'Abdominal Wall',
|
|
||||||
value: 'AbdominalWall',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Adrenal Left',
|
|
||||||
value: 'AdrenalLeft',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'B',
|
|
||||||
value: 'B',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'Brain',
|
|
||||||
value: 'Brain',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Breast',
|
|
||||||
value: 'Breast',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user