Merge remote-tracking branch 'upstream/master' into vtkjsViewportPerformance

This commit is contained in:
James A. Petts committed 2019-10-10 18:02:08 +02:00
commit a9d28d85da
45 files changed
+1961 -1586

No files matched your search

+4 -4
View File
@@ -142,8 +142,8 @@ jobs:
steps: steps:
- attach_workspace: - attach_workspace:
at: ~/repo at: ~/repo
- setup_remote_docker: # - setup_remote_docker:
docker_layer_caching: true # docker_layer_caching: true
- run: - run:
name: Build and push Docker image name: Build and push Docker image
command: | command: |
@@ -198,8 +198,8 @@ jobs:
steps: steps:
- attach_workspace: - attach_workspace:
at: ~/repo at: ~/repo
- setup_remote_docker: # - setup_remote_docker:
docker_layer_caching: true # docker_layer_caching: true
- run: - run:
name: Deploy latest version to viewer.ohif.org name: Deploy latest version to viewer.ohif.org
command: | command: |
+22
View File
@@ -3,6 +3,28 @@
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.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.3.0...@ohif/extension-cornerstone@1.3.1) (2019-10-09)
### Bug Fixes
* 🐛 set tools bidirectional, eraser and annotate command ([#1020](https://github.com/OHIF/Viewers/issues/1020)) ([a28984e](https://github.com/OHIF/Viewers/commit/a28984e))
# [1.3.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.5...@ohif/extension-cornerstone@1.3.0) (2019-10-09)
### Features
* Multiple fixes and implementation changes to react-cornerstone-viewport ([1cc94f3](https://github.com/OHIF/Viewers/commit/1cc94f3))
## [1.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.4...@ohif/extension-cornerstone@1.2.5) (2019-09-27) ## [1.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.2.4...@ohif/extension-cornerstone@1.2.5) (2019-09-27)
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-cornerstone", "name": "@ohif/extension-cornerstone",
"version": "1.2.5", "version": "1.3.1",
"description": "OHIF extension for Cornerstone", "description": "OHIF extension for Cornerstone",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -48,6 +48,6 @@
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.5.5",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"react-cornerstone-viewport": "0.1.30" "react-cornerstone-viewport": "2.x.x"
} }
} }
@@ -23,36 +23,40 @@ const MEASUREMENT_ACTION_MAP = {
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
let dataFromStore; let dataFromStore;
// TODO: This may not be updated anymore :thinking:
if (state.extensions && state.extensions.cornerstone) { if (state.extensions && state.extensions.cornerstone) {
dataFromStore = state.extensions.cornerstone; dataFromStore = state.extensions.cornerstone;
} }
// TODO: This should be extension configuration
// ...dataFromStore -->
// availableTools,
// onNewImage,
// onRightClick,
// onTouchPress,
// onTouchStart,
// onMouseClick,
// If this is the active viewport, enable prefetching. // If this is the active viewport, enable prefetching.
const { viewportIndex } = ownProps; //.viewportData; const { viewportIndex } = ownProps; //.viewportData;
const isActive = viewportIndex === state.viewports.activeViewportIndex; const isActive = viewportIndex === state.viewports.activeViewportIndex;
const viewportSpecificData = const viewportSpecificData =
state.viewports.viewportSpecificData[viewportIndex] || {}; state.viewports.viewportSpecificData[viewportIndex] || {};
// CINE
let isPlaying = false;
let frameRate = 24;
if (viewportSpecificData && viewportSpecificData.cine) {
const cine = viewportSpecificData.cine;
isPlaying = cine.isPlaying === true;
frameRate = cine.cineFrameRate || frameRate;
}
return { return {
layout: state.viewports.layout, // layout: state.viewports.layout,
isActive, isActive,
// TODO: Need a cleaner and more versatile way. // TODO: Need a cleaner and more versatile way.
// Currently justing using escape hatch + commands // Currently justing using escape hatch + commands
// activeTool: activeButton && activeButton.command, // activeTool: activeButton && activeButton.command,
...dataFromStore, ...dataFromStore,
enableStackPrefetch: isActive, isStackPrefetchEnabled: isActive,
isPlaying,
frameRate,
//stack: viewportSpecificData.stack, //stack: viewportSpecificData.stack,
cineToolData: viewportSpecificData.cine, // viewport: viewportSpecificData.viewport,
viewport: viewportSpecificData.viewport,
}; };
}; };
@@ -1,10 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import ConnectedCornerstoneViewport from "./ConnectedCornerstoneViewport"; import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
import OHIF from "@ohif/core"; import OHIF from '@ohif/core';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cornerstone from "cornerstone-core"; import cornerstone from 'cornerstone-core';
import handleSegmentationStorage from "./handleSegmentationStorage.js"; import handleSegmentationStorage from './handleSegmentationStorage.js';
const { StackManager } = OHIF.utils; const { StackManager } = OHIF.utils;
@@ -18,7 +18,7 @@ cornerstone.metaData.addProvider(
StackManager.setMetadataProvider(metadataProvider); StackManager.setMetadataProvider(metadataProvider);
const SOP_CLASSES = { const SOP_CLASSES = {
SEGMENTATION_STORAGE: "1.2.840.10008.5.1.4.1.1.66.4" SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4',
}; };
const specialCaseHandlers = {}; const specialCaseHandlers = {};
@@ -28,11 +28,11 @@ specialCaseHandlers[
class OHIFCornerstoneViewport extends Component { class OHIFCornerstoneViewport extends Component {
state = { state = {
viewportData: null viewportData: null,
}; };
static defaultProps = { static defaultProps = {
customProps: {} customProps: {},
}; };
static propTypes = { static propTypes = {
@@ -40,17 +40,17 @@ class OHIFCornerstoneViewport extends Component {
displaySet: PropTypes.object, displaySet: PropTypes.object,
viewportIndex: PropTypes.number, viewportIndex: PropTypes.number,
children: PropTypes.node, children: PropTypes.node,
customProps: PropTypes.object customProps: PropTypes.object,
}; };
static id = "OHIFCornerstoneViewport"; static id = 'OHIFCornerstoneViewport';
static init() { static init() {
console.log("OHIFCornerstoneViewport init()"); console.log('OHIFCornerstoneViewport init()');
} }
static destroy() { static destroy() {
console.log("OHIFCornerstoneViewport destroy()"); console.log('OHIFCornerstoneViewport destroy()');
StackManager.clearStacks(); StackManager.clearStacks();
} }
@@ -72,15 +72,15 @@ class OHIFCornerstoneViewport extends Component {
frameIndex = 0 frameIndex = 0
) { ) {
if (!studies || !studies.length) { if (!studies || !studies.length) {
throw new Error("Studies not provided."); throw new Error('Studies not provided.');
} }
if (!studyInstanceUid) { if (!studyInstanceUid) {
throw new Error("StudyInstanceUID not provided."); throw new Error('StudyInstanceUID not provided.');
} }
if (!displaySetInstanceUid) { if (!displaySetInstanceUid) {
throw new Error("StudyInstanceUID not provided."); throw new Error('StudyInstanceUID not provided.');
} }
// Create shortcut to displaySet // Create shortcut to displaySet
@@ -89,7 +89,7 @@ class OHIFCornerstoneViewport extends Component {
); );
if (!study) { if (!study) {
throw new Error("Study not found."); throw new Error('Study not found.');
} }
const displaySet = study.displaySets.find(set => { const displaySet = study.displaySets.find(set => {
@@ -97,7 +97,7 @@ class OHIFCornerstoneViewport extends Component {
}); });
if (!displaySet) { if (!displaySet) {
throw new Error("Display Set not found."); throw new Error('Display Set not found.');
} }
// Get stack from Stack Manager // Get stack from Stack Manager
@@ -110,7 +110,7 @@ class OHIFCornerstoneViewport extends Component {
if (sopInstanceUid) { if (sopInstanceUid) {
const index = stack.imageIds.findIndex(imageId => { const index = stack.imageIds.findIndex(imageId => {
const sopCommonModule = cornerstone.metaData.get( const sopCommonModule = cornerstone.metaData.get(
"sopCommonModule", 'sopCommonModule',
imageId imageId
); );
if (!sopCommonModule) { if (!sopCommonModule) {
@@ -124,7 +124,7 @@ class OHIFCornerstoneViewport extends Component {
stack.currentImageIdIndex = index; stack.currentImageIdIndex = index;
} else { } else {
console.warn( console.warn(
"SOPInstanceUID provided was not found in specified DisplaySet" 'SOPInstanceUID provided was not found in specified DisplaySet'
); );
} }
} }
@@ -132,22 +132,6 @@ class OHIFCornerstoneViewport extends Component {
return stack; return stack;
} }
static getViewportData = (
studies,
studyInstanceUid,
displaySetInstanceUid,
sopInstanceUid,
frameIndex
) => {
return OHIFCornerstoneViewport.getCornerstoneStack(
studies,
studyInstanceUid,
displaySetInstanceUid,
sopInstanceUid,
frameIndex
);
};
getViewportData = async ( getViewportData = async (
studies, studies,
studyInstanceUid, studyInstanceUid,
@@ -172,7 +156,7 @@ class OHIFCornerstoneViewport extends Component {
); );
break; break;
default: default:
const stack = OHIFCornerstoneViewport.getViewportData( const stack = OHIFCornerstoneViewport.getCornerstoneStack(
studies, studies,
studyInstanceUid, studyInstanceUid,
displaySetInstanceUid, displaySetInstanceUid,
@@ -183,7 +167,7 @@ class OHIFCornerstoneViewport extends Component {
viewportData = { viewportData = {
studyInstanceUid, studyInstanceUid,
displaySetInstanceUid, displaySetInstanceUid,
stack stack,
}; };
break; break;
@@ -199,7 +183,7 @@ class OHIFCornerstoneViewport extends Component {
displaySetInstanceUid, displaySetInstanceUid,
sopClassUids, sopClassUids,
sopInstanceUid, sopInstanceUid,
frameIndex frameIndex,
} = displaySet; } = displaySet;
if (!studyInstanceUid || !displaySetInstanceUid) { if (!studyInstanceUid || !displaySetInstanceUid) {
@@ -208,7 +192,7 @@ class OHIFCornerstoneViewport extends Component {
if (sopClassUids && sopClassUids.length > 1) { if (sopClassUids && sopClassUids.length > 1) {
console.warn( console.warn(
"More than one SOPClassUid in the same series is not yet supported." 'More than one SOPClassUid in the same series is not yet supported.'
); );
} }
@@ -223,7 +207,7 @@ class OHIFCornerstoneViewport extends Component {
frameIndex frameIndex
).then(viewportData => { ).then(viewportData => {
this.setState({ this.setState({
viewportData viewportData,
}); });
}); });
} }
@@ -249,25 +233,42 @@ class OHIFCornerstoneViewport extends Component {
render() { render() {
let childrenWithProps = null; let childrenWithProps = null;
if (!this.state.viewportData) {
return null;
}
const { viewportIndex } = this.props;
const {
imageIds,
currentImageIdIndex,
// If this comes from the instance, would be a better default
// `FrameTime` in the instance
// frameRate = 0,
} = this.state.viewportData.stack;
// TODO: Does it make more sense to use Context? // TODO: Does it make more sense to use Context?
if (this.props.children && this.props.children.length) { if (this.props.children && this.props.children.length) {
childrenWithProps = this.props.children.map((child, index) => { childrenWithProps = this.props.children.map((child, index) => {
return React.cloneElement(child, { return React.cloneElement(child, {
viewportIndex: this.props.viewportIndex, viewportIndex: this.props.viewportIndex,
key: index key: index,
}); });
}); });
} }
return ( return (
<> <>
{this.state.viewportData && ( <ConnectedCornerstoneViewport
<ConnectedCornerstoneViewport viewportIndex={viewportIndex}
viewportData={this.state.viewportData} imageIds={imageIds}
viewportIndex={this.props.viewportIndex} imageIdIndex={currentImageIdIndex}
{...this.props.customProps} // ~~ Connected (From REDUX)
/> // frameRate={frameRate}
)} // isPlaying={false}
// isStackPrefetchEnabled={true}
// onElementEnabled={() => {}}
// setViewportActive{() => {}}
{...this.props.customProps}
/>
{childrenWithProps} {childrenWithProps}
</> </>
); );
+15 -1
View File
@@ -1,8 +1,13 @@
import init from './init.js';
import asyncComponent from './asyncComponent.js'; import asyncComponent from './asyncComponent.js';
import commandsModule from './commandsModule.js'; import commandsModule from './commandsModule.js';
import toolbarModule from './toolbarModule.js'; import toolbarModule from './toolbarModule.js';
const OHIFCornerstoneViewport = asyncComponent(() => import( /* webpackChunkName: "OHIFCornerstoneViewport" */ './OHIFCornerstoneViewport.js')); const OHIFCornerstoneViewport = asyncComponent(() =>
import(
/* webpackChunkName: "OHIFCornerstoneViewport" */ './OHIFCornerstoneViewport.js'
)
);
/** /**
* *
@@ -13,6 +18,15 @@ export default {
*/ */
id: 'cornerstone', id: 'cornerstone',
/**
*
*
* @param {object} [configuration={}]
* @param {object|array} [configuration.csToolsConfig] - Passed directly to `initCornerstoneTools`
*/
preRegistration(configuration = {}) {
init(configuration);
},
getViewportModule() { getViewportModule() {
return OHIFCornerstoneViewport; return OHIFCornerstoneViewport;
}, },
+87
View File
@@ -0,0 +1,87 @@
import OHIF from '@ohif/core';
import cornerstone from 'cornerstone-core';
import csTools from 'cornerstone-tools';
import initCornerstoneTools from './initCornerstoneTools.js';
/**
*
* @param {object} configuration
* @param {Object|Array} configuration.csToolsConfig
*/
export default function init(configuration = {}) {
const { csToolsConfig } = configuration;
const { StackManager } = OHIF.utils;
const metadataProvider = new OHIF.cornerstone.MetadataProvider();
// ~~ Set our MetadataProvider
cornerstone.metaData.addProvider(
metadataProvider.provider.bind(metadataProvider)
);
StackManager.setMetadataProvider(metadataProvider);
// ~~
const defaultCsToolsConfig = csToolsConfig || {
globalToolSyncEnabled: true,
showSVGCursors: true,
autoResizeViewports: false,
};
initCornerstoneTools(defaultCsToolsConfig);
// ~~ Toooools 🙌
const {
PanTool,
ZoomTool,
WwwcTool,
MagnifyTool,
StackScrollTool,
StackScrollMouseWheelTool,
// Touch
PanMultiTouchTool,
ZoomTouchPinchTool,
// Annotations
EraserTool,
ArrowAnnotateTool,
BidirectionalTool,
LengthTool,
AngleTool,
FreehandRoiTool,
EllipticalRoiTool,
DragProbeTool,
RectangleRoiTool,
// Segmentation
BrushTool,
} = csTools;
const tools = [
PanTool,
ZoomTool,
WwwcTool,
MagnifyTool,
StackScrollTool,
StackScrollMouseWheelTool,
// Touch
PanMultiTouchTool,
ZoomTouchPinchTool,
// Annotations
EraserTool,
ArrowAnnotateTool,
BidirectionalTool,
LengthTool,
AngleTool,
FreehandRoiTool,
EllipticalRoiTool,
DragProbeTool,
RectangleRoiTool,
// Segmentation
BrushTool,
];
tools.forEach(tool => csTools.addTool(tool));
csTools.setToolActive('Pan', { mouseButtonMask: 4 });
csTools.setToolActive('Zoom', { mouseButtonMask: 2 });
csTools.setToolActive('Wwwc', { mouseButtonMask: 1 });
csTools.setToolActive('StackScrollMouseWheel', {}); // TODO: Empty options should not be required
csTools.setToolActive('PanMultiTouch', { pointers: 2 }); // TODO: Better error if no options
csTools.setToolActive('ZoomTouchPinch', {});
}
+3 -3
View File
@@ -74,7 +74,7 @@ const definitions = [
label: 'Annotate', label: 'Annotate',
icon: 'measure-non-target', icon: 'measure-non-target',
// //
type: TOOLBAR_BUTTON_TYPES.COMMAND, type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive', commandName: 'setToolActive',
commandOptions: { toolName: 'ArrowAnnotate' }, commandOptions: { toolName: 'ArrowAnnotate' },
}, },
@@ -200,7 +200,7 @@ const definitions = [
label: 'Bidirectional', label: 'Bidirectional',
icon: 'measure-target', icon: 'measure-target',
// //
type: TOOLBAR_BUTTON_TYPES.COMMAND, type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive', commandName: 'setToolActive',
commandOptions: { toolName: 'Bidirectional' }, commandOptions: { toolName: 'Bidirectional' },
}, },
@@ -209,7 +209,7 @@ const definitions = [
label: 'Eraser', label: 'Eraser',
icon: 'eraser', icon: 'eraser',
// //
type: TOOLBAR_BUTTON_TYPES.COMMAND, type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive', commandName: 'setToolActive',
commandOptions: { toolName: 'Eraser' }, commandOptions: { toolName: 'Eraser' },
}, },
+16
View File
@@ -3,6 +3,22 @@
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.52.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.3...@ohif/extension-vtk@0.52.4) (2019-10-10)
**Note:** Version bump only for package @ohif/extension-vtk
## [0.52.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.2...@ohif/extension-vtk@0.52.3) (2019-10-09)
**Note:** Version bump only for package @ohif/extension-vtk
## [0.52.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.1...@ohif/extension-vtk@0.52.2) (2019-10-09) ## [0.52.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.1...@ohif/extension-vtk@0.52.2) (2019-10-09)
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-vtk", "name": "@ohif/extension-vtk",
"version": "0.52.2", "version": "0.52.4",
"description": "OHIF extension for VTK.js", "description": "OHIF extension for VTK.js",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -52,7 +52,7 @@
}, },
"devDependencies": { "devDependencies": {
"@ohif/core": "^1.2.0", "@ohif/core": "^1.2.0",
"@ohif/ui": "^0.53.1", "@ohif/ui": "^0.53.3",
"cornerstone-tools": "^4.0.9", "cornerstone-tools": "^4.0.9",
"cornerstone-wado-image-loader": "^3.0.0", "cornerstone-wado-image-loader": "^3.0.0",
"dcmjs": "^0.6.1", "dcmjs": "^0.6.1",
+19
View File
@@ -3,6 +3,25 @@
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.53.3](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.53.2...@ohif/ui@0.53.3) (2019-10-10)
### Bug Fixes
* 🎸 switch ohif logo from text + font to SVG ([#1021](https://github.com/OHIF/Viewers/issues/1021)) ([e7de8be](https://github.com/OHIF/Viewers/commit/e7de8be))
## [0.53.2](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.53.1...@ohif/ui@0.53.2) (2019-10-09)
**Note:** Version bump only for package @ohif/ui
## [0.53.1](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.53.0...@ohif/ui@0.53.1) (2019-10-04) ## [0.53.1](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.53.0...@ohif/ui@0.53.1) (2019-10-04)
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/ui", "name": "@ohif/ui",
"version": "0.53.1", "version": "0.53.3",
"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",
+2 -2
View File
@@ -33,8 +33,8 @@ as easy as possible. You will, however, need to include either the default font
or the font you set for your theme: or the font you set for your theme:
```js ```js
// Google Fonts, Sanchez & Roboto // Google Fonts, Roboto
'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap'; '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 `@ohif/ui` also looks for theme CSS variabled defined on `:root`. You can find a
+21 -18
View File
@@ -1,18 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ lang }}"> <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> <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">
<!-- Latest compiled and minified CSS --> <title>{{ title }}</title>
<link rel="stylesheet" href="/public/docz.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap">
<style> <!-- 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 */ /* "Tide" theme */
/* TODO: /* TODO:
- Convert the other themes to CSS Variables - Convert the other themes to CSS Variables
@@ -40,7 +41,7 @@
--table-text-primary-color: #ffffff; --table-text-primary-color: #ffffff;
--table-text-secondary-color: #91b9cd; --table-text-secondary-color: #91b9cd;
--large-numbers-color:#6FBDE2; --large-numbers-color: #6FBDE2;
--state-error: #FFCCCC; --state-error: #FFCCCC;
--state-error-border: #FFCCCC; --state-error-border: #FFCCCC;
@@ -70,11 +71,13 @@
body { body {
font-family: 'Roboto', sans-serif !important; font-family: 'Roboto', sans-serif !important;
} }
</style> </style>
{{ head }} {{ head }}
</head> </head>
<body>
<div id="root" /> <body>
{{ footer }} <div id="root" />
</body> {{ footer }}
</body>
</html> </html>
@@ -35,7 +35,7 @@ class StudyBrowser extends Component {
); );
} else { } else {
return ( return (
<div className="ThumbnailEntryContainer"> <div className="ThumbnailEntryContainer" data-cy="thumbnail-list">
<ThumbnailEntry <ThumbnailEntry
key={thumb.displaySetInstanceUid} key={thumb.displaySetInstanceUid}
{...study} {...study}
@@ -45,7 +45,7 @@ class ThumbnailEntryDragSource extends Component {
const dropEffect = 'copy'; const dropEffect = 'copy';
return connectDragSource( return connectDragSource(
<div className="ThumbnailEntryContainer"> <div className="ThumbnailEntryContainer" data-cy="thumbnail-list">
<DragPreview {...this.props} /> <DragPreview {...this.props} />
<ThumbnailEntry {...this.props} /> <ThumbnailEntry {...this.props} />
</div>, </div>,
+2
View File
@@ -53,6 +53,7 @@ import measureTargetUn from './icons/measure-target-un.svg';
import measureTemp from './icons/measure-temp.svg'; import measureTemp from './icons/measure-temp.svg';
import objectGroup from './icons/object-group.svg'; import objectGroup from './icons/object-group.svg';
import ohifLogo from './icons/ohif-logo.svg'; import ohifLogo from './icons/ohif-logo.svg';
import ohifTextLogo from './icons/ohif-text-logo.svg';
import oval from './icons/oval.svg'; import oval from './icons/oval.svg';
import palette from './icons/palette.svg'; import palette from './icons/palette.svg';
import play from './icons/play.svg'; import play from './icons/play.svg';
@@ -120,6 +121,7 @@ const ICONS = {
'inline-edit': inlineEdit, 'inline-edit': inlineEdit,
list, list,
'ohif-logo': ohifLogo, 'ohif-logo': ohifLogo,
'ohif-text-logo': ohifTextLogo,
lock, lock,
play, play,
database, database,
@@ -0,0 +1,3 @@
<svg viewBox="0 0 224 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.416 5.932C10.416 7.46267 9.954 8.70867 9.03 9.67C8.11533 10.622 6.958 11.098 5.558 11.098C4.16733 11.098 3.00533 10.6173 2.072 9.656C1.13867 8.68533 0.672 7.43933 0.672 5.918C0.672 4.38733 1.15267 3.16467 2.114 2.25C3.07533 1.326 4.22333 0.863999 5.558 0.863999C6.89267 0.863999 8.036 1.326 8.988 2.25C9.94 3.16467 10.416 4.392 10.416 5.932ZM3.052 8.9C3.77067 9.60933 4.606 9.964 5.558 9.964C6.51 9.964 7.34067 9.60933 8.05 8.9C8.75933 8.18133 9.114 7.20133 9.114 5.96C9.114 4.70933 8.75 3.734 8.022 3.034C7.30333 2.32467 6.482 1.97 5.558 1.97C4.634 1.97 3.808 2.32467 3.08 3.034C2.352 3.734 1.988 4.70933 1.988 5.96C1.988 7.20133 2.34267 8.18133 3.052 8.9ZM14.6296 14.15H11.8156C11.6942 14.15 11.6336 14.094 11.6336 13.982V13.38C11.6336 13.268 11.6942 13.212 11.8156 13.212H12.5996V5.05H11.8436C11.7222 5.05 11.6616 4.994 11.6616 4.882V4.28C11.6616 4.168 11.7222 4.112 11.8436 4.112H13.4816C13.6029 4.112 13.6636 4.168 13.6636 4.28L13.6496 5.386H13.6636C13.8409 5.00333 14.1256 4.68133 14.5176 4.42C14.9189 4.14933 15.4089 4.014 15.9876 4.014C16.9302 4.014 17.6909 4.336 18.2696 4.98C18.8482 5.61467 19.1376 6.464 19.1376 7.528C19.1376 8.58267 18.8529 9.44133 18.2836 10.104C17.7142 10.7667 16.9536 11.098 16.0016 11.098C15.4229 11.098 14.9376 10.9673 14.5456 10.706C14.1629 10.4353 13.8876 10.1087 13.7196 9.726H13.6776C13.7056 10.0247 13.7196 10.2393 13.7196 10.37V13.212H14.6296C14.7509 13.212 14.8116 13.268 14.8116 13.38V13.982C14.8116 14.094 14.7509 14.15 14.6296 14.15ZM13.6916 7.584C13.6916 8.396 13.9016 9.02133 14.3216 9.46C14.7509 9.89867 15.2642 10.118 15.8616 10.118C16.4682 10.118 16.9722 9.88467 17.3736 9.418C17.7842 8.942 17.9896 8.32133 17.9896 7.556C17.9896 6.78133 17.7842 6.16067 17.3736 5.694C16.9722 5.22733 16.4682 4.994 15.8616 4.994C15.2549 4.994 14.7416 5.22267 14.3216 5.68C13.9016 6.13733 13.6916 6.772 13.6916 7.584ZM26.3811 7.696H21.3411C21.3785 8.47067 21.6211 9.068 22.0691 9.488C22.5265 9.908 23.0398 10.118 23.6091 10.118C24.1785 10.118 24.6638 9.99667 25.0651 9.754C25.4758 9.51133 25.7511 9.27333 25.8911 9.04C25.9658 8.94667 26.0498 8.93267 26.1431 8.998L26.5211 9.376C26.5771 9.432 26.6051 9.48333 26.6051 9.53C26.6051 9.56733 26.5818 9.61867 26.5351 9.684C26.4978 9.74933 26.4138 9.852 26.2831 9.992C26.1525 10.132 25.9658 10.2907 25.7231 10.468C25.4898 10.6453 25.1818 10.7947 24.7991 10.916C24.4258 11.0373 24.0245 11.098 23.5951 11.098C22.6151 11.098 21.7938 10.776 21.1311 10.132C20.4778 9.488 20.1511 8.62467 20.1511 7.542C20.1511 6.45 20.4778 5.59133 21.1311 4.966C21.7845 4.33133 22.5825 4.014 23.5251 4.014C24.4771 4.014 25.2238 4.322 25.7651 4.938C26.3065 5.54467 26.5771 6.366 26.5771 7.402C26.5771 7.43933 26.5771 7.47667 26.5771 7.514C26.5771 7.63533 26.5118 7.696 26.3811 7.696ZM25.4151 6.842C25.3871 6.26333 25.2051 5.80133 24.8691 5.456C24.5331 5.11067 24.0851 4.938 23.5251 4.938C22.9651 4.938 22.4845 5.09667 22.0831 5.414C21.6818 5.73133 21.4438 6.20733 21.3691 6.842H25.4151ZM35.1323 11H33.8023C33.401 11 33.2003 10.804 33.2003 10.412V6.73C33.2003 6.18867 33.0697 5.76867 32.8083 5.47C32.547 5.17133 32.1643 5.022 31.6603 5.022C30.9417 5.022 30.3817 5.316 29.9803 5.904C29.9337 5.96 29.873 6.06267 29.7983 6.212V10.062H30.5403C30.6617 10.062 30.7223 10.118 30.7223 10.23V10.832C30.7223 10.944 30.6617 11 30.5403 11H27.8663C27.745 11 27.6843 10.944 27.6843 10.832V10.23C27.6843 10.118 27.745 10.062 27.8663 10.062H28.6363V5.05H27.8663C27.745 5.05 27.6843 4.994 27.6843 4.882V4.28C27.6843 4.168 27.745 4.112 27.8663 4.112H29.5043C29.6257 4.112 29.6863 4.168 29.6863 4.28L29.6583 5.232H29.7003C30.1857 4.42 30.937 4.014 31.9543 4.014C32.701 4.014 33.2843 4.23333 33.7043 4.672C34.1243 5.11067 34.339 5.70333 34.3483 6.45V10.062H35.1323C35.2537 10.062 35.3143 10.118 35.3143 10.23V10.832C35.3143 10.944 35.2537 11 35.1323 11ZM50.8763 11H47.5023C47.3903 11 47.3343 10.944 47.3343 10.832V10.118C47.3343 10.006 47.3903 9.95 47.5023 9.95H48.5803V6.52H43.3723V9.95H44.4503C44.5717 9.95 44.6323 10.006 44.6323 10.118V10.832C44.6323 10.944 44.5717 11 44.4503 11H41.0903C40.969 11 40.9083 10.944 40.9083 10.832V10.118C40.9083 10.006 40.969 9.95 41.0903 9.95H42.1543V1.998H41.0903C40.969 1.998 40.9083 1.942 40.9083 1.83V1.116C40.9083 1.004 40.969 0.947999 41.0903 0.947999H44.4503C44.5717 0.947999 44.6323 1.004 44.6323 1.116V1.83C44.6323 1.942 44.5717 1.998 44.4503 1.998H43.3723V5.498H48.5803V1.998H47.5023C47.3903 1.998 47.3343 1.942 47.3343 1.83V1.116C47.3343 1.004 47.3903 0.947999 47.5023 0.947999H50.8763C50.9883 0.947999 51.0443 1.004 51.0443 1.116V1.83C51.0443 1.942 50.9883 1.998 50.8763 1.998H49.7983V9.95H50.8763C50.9883 9.95 51.0443 10.006 51.0443 10.118V10.832C51.0443 10.944 50.9883 11 50.8763 11ZM58.0452 7.696H53.0052C53.0425 8.47067 53.2852 9.068 53.7332 9.488C54.1905 9.908 54.7039 10.118 55.2732 10.118C55.8425 10.118 56.3279 9.99667 56.7292 9.754C57.1399 9.51133 57.4152 9.27333 57.5552 9.04C57.6299 8.94667 57.7139 8.93267 57.8072 8.998L58.1852 9.376C58.2412 9.432 58.2692 9.48333 58.2692 9.53C58.2692 9.56733 58.245Line truncated
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

@@ -1,3 +1,3 @@
<svg width="3.73em" height=".25em" viewBox="0 0 224 15" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 224 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.416 5.932C10.416 7.46267 9.954 8.70867 9.03 9.67C8.11533 10.622 6.958 11.098 5.558 11.098C4.16733 11.098 3.00533 10.6173 2.072 9.656C1.13867 8.68533 0.672 7.43933 0.672 5.918C0.672 4.38733 1.15267 3.16467 2.114 2.25C3.07533 1.326 4.22333 0.863999 5.558 0.863999C6.89267 0.863999 8.036 1.326 8.988 2.25C9.94 3.16467 10.416 4.392 10.416 5.932ZM3.052 8.9C3.77067 9.60933 4.606 9.964 5.558 9.964C6.51 9.964 7.34067 9.60933 8.05 8.9C8.75933 8.18133 9.114 7.20133 9.114 5.96C9.114 4.70933 8.75 3.734 8.022 3.034C7.30333 2.32467 6.482 1.97 5.558 1.97C4.634 1.97 3.808 2.32467 3.08 3.034C2.352 3.734 1.988 4.70933 1.988 5.96C1.988 7.20133 2.34267 8.18133 3.052 8.9ZM14.6296 14.15H11.8156C11.6942 14.15 11.6336 14.094 11.6336 13.982V13.38C11.6336 13.268 11.6942 13.212 11.8156 13.212H12.5996V5.05H11.8436C11.7222 5.05 11.6616 4.994 11.6616 4.882V4.28C11.6616 4.168 11.7222 4.112 11.8436 4.112H13.4816C13.6029 4.112 13.6636 4.168 13.6636 4.28L13.6496 5.386H13.6636C13.8409 5.00333 14.1256 4.68133 14.5176 4.42C14.9189 4.14933 15.4089 4.014 15.9876 4.014C16.9302 4.014 17.6909 4.336 18.2696 4.98C18.8482 5.61467 19.1376 6.464 19.1376 7.528C19.1376 8.58267 18.8529 9.44133 18.2836 10.104C17.7142 10.7667 16.9536 11.098 16.0016 11.098C15.4229 11.098 14.9376 10.9673 14.5456 10.706C14.1629 10.4353 13.8876 10.1087 13.7196 9.726H13.6776C13.7056 10.0247 13.7196 10.2393 13.7196 10.37V13.212H14.6296C14.7509 13.212 14.8116 13.268 14.8116 13.38V13.982C14.8116 14.094 14.7509 14.15 14.6296 14.15ZM13.6916 7.584C13.6916 8.396 13.9016 9.02133 14.3216 9.46C14.7509 9.89867 15.2642 10.118 15.8616 10.118C16.4682 10.118 16.9722 9.88467 17.3736 9.418C17.7842 8.942 17.9896 8.32133 17.9896 7.556C17.9896 6.78133 17.7842 6.16067 17.3736 5.694C16.9722 5.22733 16.4682 4.994 15.8616 4.994C15.2549 4.994 14.7416 5.22267 14.3216 5.68C13.9016 6.13733 13.6916 6.772 13.6916 7.584ZM26.3811 7.696H21.3411C21.3785 8.47067 21.6211 9.068 22.0691 9.488C22.5265 9.908 23.0398 10.118 23.6091 10.118C24.1785 10.118 24.6638 9.99667 25.0651 9.754C25.4758 9.51133 25.7511 9.27333 25.8911 9.04C25.9658 8.94667 26.0498 8.93267 26.1431 8.998L26.5211 9.376C26.5771 9.432 26.6051 9.48333 26.6051 9.53C26.6051 9.56733 26.5818 9.61867 26.5351 9.684C26.4978 9.74933 26.4138 9.852 26.2831 9.992C26.1525 10.132 25.9658 10.2907 25.7231 10.468C25.4898 10.6453 25.1818 10.7947 24.7991 10.916C24.4258 11.0373 24.0245 11.098 23.5951 11.098C22.6151 11.098 21.7938 10.776 21.1311 10.132C20.4778 9.488 20.1511 8.62467 20.1511 7.542C20.1511 6.45 20.4778 5.59133 21.1311 4.966C21.7845 4.33133 22.5825 4.014 23.5251 4.014C24.4771 4.014 25.2238 4.322 25.7651 4.938C26.3065 5.54467 26.5771 6.366 26.5771 7.402C26.5771 7.43933 26.5771 7.47667 26.5771 7.514C26.5771 7.63533 26.5118 7.696 26.3811 7.696ZM25.4151 6.842C25.3871 6.26333 25.2051 5.80133 24.8691 5.456C24.5331 5.11067 24.0851 4.938 23.5251 4.938C22.9651 4.938 22.4845 5.09667 22.0831 5.414C21.6818 5.73133 21.4438 6.20733 21.3691 6.842H25.4151ZM35.1323 11H33.8023C33.401 11 33.2003 10.804 33.2003 10.412V6.73C33.2003 6.18867 33.0697 5.76867 32.8083 5.47C32.547 5.17133 32.1643 5.022 31.6603 5.022C30.9417 5.022 30.3817 5.316 29.9803 5.904C29.9337 5.96 29.873 6.06267 29.7983 6.212V10.062H30.5403C30.6617 10.062 30.7223 10.118 30.7223 10.23V10.832C30.7223 10.944 30.6617 11 30.5403 11H27.8663C27.745 11 27.6843 10.944 27.6843 10.832V10.23C27.6843 10.118 27.745 10.062 27.8663 10.062H28.6363V5.05H27.8663C27.745 5.05 27.6843 4.994 27.6843 4.882V4.28C27.6843 4.168 27.745 4.112 27.8663 4.112H29.5043C29.6257 4.112 29.6863 4.168 29.6863 4.28L29.6583 5.232H29.7003C30.1857 4.42 30.937 4.014 31.9543 4.014C32.701 4.014 33.2843 4.23333 33.7043 4.672C34.1243 5.11067 34.339 5.70333 34.3483 6.45V10.062H35.1323C35.2537 10.062 35.3143 10.118 35.3143 10.23V10.832C35.3143 10.944 35.2537 11 35.1323 11ZM50.8763 11H47.5023C47.3903 11 47.3343 10.944 47.3343 10.832V10.118C47.3343 10.006 47.3903 9.95 47.5023 9.95H48.5803V6.52H43.3723V9.95H44.4503C44.5717 9.95 44.6323 10.006 44.6323 10.118V10.832C44.6323 10.944 44.5717 11 44.4503 11H41.0903C40.969 11 40.9083 10.944 40.9083 10.832V10.118C40.9083 10.006 40.969 9.95 41.0903 9.95H42.1543V1.998H41.0903C40.969 1.998 40.9083 1.942 40.9083 1.83V1.116C40.9083 1.004 40.969 0.947999 41.0903 0.947999H44.4503C44.5717 0.947999 44.6323 1.004 44.6323 1.116V1.83C44.6323 1.942 44.5717 1.998 44.4503 1.998H43.3723V5.498H48.5803V1.998H47.5023C47.3903 1.998 47.3343 1.942 47.3343 1.83V1.116C47.3343 1.004 47.3903 0.947999 47.5023 0.947999H50.8763C50.9883 0.947999 51.0443 1.004 51.0443 1.116V1.83C51.0443 1.942 50.9883 1.998 50.8763 1.998H49.7983V9.95H50.8763C50.9883 9.95 51.0443 10.006 51.0443 10.118V10.832C51.0443 10.944 50.9883 11 50.8763 11ZM58.0452 7.696H53.0052C53.0425 8.47067 53.2852 9.068 53.7332 9.488C54.1905 9.908 54.7039 10.118 55.2732 10.118C55.8425 10.118 56.3279 9.99667 56.7292 9.754C57.1399 9.51133 57.4152 9.27333 57.5552 9.04C57.6299 8.94667 57.7139 8.93267 57.8072 8.998L58.1852 9.376C58.2412 9.432 58.2692 9.48333 58.2692 9.53C58.2692 9.56733 58.245Line truncated <path d="M10.416 5.932C10.416 7.46267 9.954 8.70867 9.03 9.67C8.11533 10.622 6.958 11.098 5.558 11.098C4.16733 11.098 3.00533 10.6173 2.072 9.656C1.13867 8.68533 0.672 7.43933 0.672 5.918C0.672 4.38733 1.15267 3.16467 2.114 2.25C3.07533 1.326 4.22333 0.863999 5.558 0.863999C6.89267 0.863999 8.036 1.326 8.988 2.25C9.94 3.16467 10.416 4.392 10.416 5.932ZM3.052 8.9C3.77067 9.60933 4.606 9.964 5.558 9.964C6.51 9.964 7.34067 9.60933 8.05 8.9C8.75933 8.18133 9.114 7.20133 9.114 5.96C9.114 4.70933 8.75 3.734 8.022 3.034C7.30333 2.32467 6.482 1.97 5.558 1.97C4.634 1.97 3.808 2.32467 3.08 3.034C2.352 3.734 1.988 4.70933 1.988 5.96C1.988 7.20133 2.34267 8.18133 3.052 8.9ZM14.6296 14.15H11.8156C11.6942 14.15 11.6336 14.094 11.6336 13.982V13.38C11.6336 13.268 11.6942 13.212 11.8156 13.212H12.5996V5.05H11.8436C11.7222 5.05 11.6616 4.994 11.6616 4.882V4.28C11.6616 4.168 11.7222 4.112 11.8436 4.112H13.4816C13.6029 4.112 13.6636 4.168 13.6636 4.28L13.6496 5.386H13.6636C13.8409 5.00333 14.1256 4.68133 14.5176 4.42C14.9189 4.14933 15.4089 4.014 15.9876 4.014C16.9302 4.014 17.6909 4.336 18.2696 4.98C18.8482 5.61467 19.1376 6.464 19.1376 7.528C19.1376 8.58267 18.8529 9.44133 18.2836 10.104C17.7142 10.7667 16.9536 11.098 16.0016 11.098C15.4229 11.098 14.9376 10.9673 14.5456 10.706C14.1629 10.4353 13.8876 10.1087 13.7196 9.726H13.6776C13.7056 10.0247 13.7196 10.2393 13.7196 10.37V13.212H14.6296C14.7509 13.212 14.8116 13.268 14.8116 13.38V13.982C14.8116 14.094 14.7509 14.15 14.6296 14.15ZM13.6916 7.584C13.6916 8.396 13.9016 9.02133 14.3216 9.46C14.7509 9.89867 15.2642 10.118 15.8616 10.118C16.4682 10.118 16.9722 9.88467 17.3736 9.418C17.7842 8.942 17.9896 8.32133 17.9896 7.556C17.9896 6.78133 17.7842 6.16067 17.3736 5.694C16.9722 5.22733 16.4682 4.994 15.8616 4.994C15.2549 4.994 14.7416 5.22267 14.3216 5.68C13.9016 6.13733 13.6916 6.772 13.6916 7.584ZM26.3811 7.696H21.3411C21.3785 8.47067 21.6211 9.068 22.0691 9.488C22.5265 9.908 23.0398 10.118 23.6091 10.118C24.1785 10.118 24.6638 9.99667 25.0651 9.754C25.4758 9.51133 25.7511 9.27333 25.8911 9.04C25.9658 8.94667 26.0498 8.93267 26.1431 8.998L26.5211 9.376C26.5771 9.432 26.6051 9.48333 26.6051 9.53C26.6051 9.56733 26.5818 9.61867 26.5351 9.684C26.4978 9.74933 26.4138 9.852 26.2831 9.992C26.1525 10.132 25.9658 10.2907 25.7231 10.468C25.4898 10.6453 25.1818 10.7947 24.7991 10.916C24.4258 11.0373 24.0245 11.098 23.5951 11.098C22.6151 11.098 21.7938 10.776 21.1311 10.132C20.4778 9.488 20.1511 8.62467 20.1511 7.542C20.1511 6.45 20.4778 5.59133 21.1311 4.966C21.7845 4.33133 22.5825 4.014 23.5251 4.014C24.4771 4.014 25.2238 4.322 25.7651 4.938C26.3065 5.54467 26.5771 6.366 26.5771 7.402C26.5771 7.43933 26.5771 7.47667 26.5771 7.514C26.5771 7.63533 26.5118 7.696 26.3811 7.696ZM25.4151 6.842C25.3871 6.26333 25.2051 5.80133 24.8691 5.456C24.5331 5.11067 24.0851 4.938 23.5251 4.938C22.9651 4.938 22.4845 5.09667 22.0831 5.414C21.6818 5.73133 21.4438 6.20733 21.3691 6.842H25.4151ZM35.1323 11H33.8023C33.401 11 33.2003 10.804 33.2003 10.412V6.73C33.2003 6.18867 33.0697 5.76867 32.8083 5.47C32.547 5.17133 32.1643 5.022 31.6603 5.022C30.9417 5.022 30.3817 5.316 29.9803 5.904C29.9337 5.96 29.873 6.06267 29.7983 6.212V10.062H30.5403C30.6617 10.062 30.7223 10.118 30.7223 10.23V10.832C30.7223 10.944 30.6617 11 30.5403 11H27.8663C27.745 11 27.6843 10.944 27.6843 10.832V10.23C27.6843 10.118 27.745 10.062 27.8663 10.062H28.6363V5.05H27.8663C27.745 5.05 27.6843 4.994 27.6843 4.882V4.28C27.6843 4.168 27.745 4.112 27.8663 4.112H29.5043C29.6257 4.112 29.6863 4.168 29.6863 4.28L29.6583 5.232H29.7003C30.1857 4.42 30.937 4.014 31.9543 4.014C32.701 4.014 33.2843 4.23333 33.7043 4.672C34.1243 5.11067 34.339 5.70333 34.3483 6.45V10.062H35.1323C35.2537 10.062 35.3143 10.118 35.3143 10.23V10.832C35.3143 10.944 35.2537 11 35.1323 11ZM50.8763 11H47.5023C47.3903 11 47.3343 10.944 47.3343 10.832V10.118C47.3343 10.006 47.3903 9.95 47.5023 9.95H48.5803V6.52H43.3723V9.95H44.4503C44.5717 9.95 44.6323 10.006 44.6323 10.118V10.832C44.6323 10.944 44.5717 11 44.4503 11H41.0903C40.969 11 40.9083 10.944 40.9083 10.832V10.118C40.9083 10.006 40.969 9.95 41.0903 9.95H42.1543V1.998H41.0903C40.969 1.998 40.9083 1.942 40.9083 1.83V1.116C40.9083 1.004 40.969 0.947999 41.0903 0.947999H44.4503C44.5717 0.947999 44.6323 1.004 44.6323 1.116V1.83C44.6323 1.942 44.5717 1.998 44.4503 1.998H43.3723V5.498H48.5803V1.998H47.5023C47.3903 1.998 47.3343 1.942 47.3343 1.83V1.116C47.3343 1.004 47.3903 0.947999 47.5023 0.947999H50.8763C50.9883 0.947999 51.0443 1.004 51.0443 1.116V1.83C51.0443 1.942 50.9883 1.998 50.8763 1.998H49.7983V9.95H50.8763C50.9883 9.95 51.0443 10.006 51.0443 10.118V10.832C51.0443 10.944 50.9883 11 50.8763 11ZM58.0452 7.696H53.0052C53.0425 8.47067 53.2852 9.068 53.7332 9.488C54.1905 9.908 54.7039 10.118 55.2732 10.118C55.8425 10.118 56.3279 9.99667 56.7292 9.754C57.1399 9.51133 57.4152 9.27333 57.5552 9.04C57.6299 8.94667 57.7139 8.93267 57.8072 8.998L58.1852 9.376C58.2412 9.432 58.2692 9.48333 58.2692 9.53C58.2692 9.56733 58.245Line truncated
</svg> </svg>

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

+8 -6
View File
@@ -25,11 +25,13 @@ const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js'; const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
const PROXY_TARGET = process.env.PROXY_TARGET; const PROXY_TARGET = process.env.PROXY_TARGET;
const PROXY_DOMAIN = process.env.PROXY_DOMAIN; const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
const SKIP_MINIMIZE = process.env.SKIP_MINIMIZE;
module.exports = (env, argv) => { module.exports = (env, argv) => {
const baseConfig = webpackBase(env, argv, { SRC_DIR, DIST_DIR }); const baseConfig = webpackBase(env, argv, { SRC_DIR, DIST_DIR });
const isProdBuild = process.env.NODE_ENV === 'production'; const isProdBuild = process.env.NODE_ENV === 'production';
const hasProxy = PROXY_TARGET && PROXY_DOMAIN; const hasProxy = PROXY_TARGET && PROXY_DOMAIN;
const skipMinimize = SKIP_MINIMIZE === 'true';
const mergedConfig = merge(baseConfig, { const mergedConfig = merge(baseConfig, {
devtool: isProdBuild ? 'source-map' : 'cheap-module-eval-source-map', devtool: isProdBuild ? 'source-map' : 'cheap-module-eval-source-map',
@@ -50,7 +52,7 @@ module.exports = (env, argv) => {
warnings: true, warnings: true,
}, },
optimization: { optimization: {
minimize: isProdBuild, minimize: isProdBuild && !skipMinimize,
sideEffects: true, sideEffects: true,
}, },
module: { module: {
@@ -85,8 +87,8 @@ module.exports = (env, argv) => {
]), ]),
// https://github.com/faceyspacey/extract-css-chunks-webpack-plugin#webpack-4-standalone-installation // https://github.com/faceyspacey/extract-css-chunks-webpack-plugin#webpack-4-standalone-installation
new ExtractCssChunksPlugin({ new ExtractCssChunksPlugin({
filename: '[name].css', filename: isProdBuild ? '[name].[hash].css' : '[name].css',
chunkFilename: '[id].css', chunkFilename: isProdBuild ? '[id].[hash].css' : '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order ignoreOrder: false, // Enable to remove warnings about conflicting order
}), }),
// Generate "index.html" w/ correct includes/imports // Generate "index.html" w/ correct includes/imports
@@ -129,14 +131,14 @@ module.exports = (env, argv) => {
if (!isProdBuild) { if (!isProdBuild) {
mergedConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); mergedConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
} else {
//
mergedConfig.optimization.minimizer = [ mergedConfig.optimization.minimizer = [
new TerserJSPlugin({ new TerserJSPlugin({
sourceMap: true, sourceMap: true,
parallel: true, parallel: true,
}), }),
new OptimizeCSSAssetsPlugin({}), // No bueno
// new OptimizeCSSAssetsPlugin({}),
]; ];
} }
+33
View File
@@ -3,6 +3,39 @@
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.5.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.5.1...@ohif/viewer@1.5.2) (2019-10-10)
### Bug Fixes
* 🎸 switch ohif logo from text + font to SVG ([#1021](https://github.com/OHIF/Viewers/issues/1021)) ([e7de8be](https://github.com/OHIF/Viewers/commit/e7de8be))
## [1.5.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.5.0...@ohif/viewer@1.5.1) (2019-10-09)
### Bug Fixes
* 🐛 set current viewport as active when switching layouts ([#1018](https://github.com/OHIF/Viewers/issues/1018)) ([2a74355](https://github.com/OHIF/Viewers/commit/2a74355))
# [1.5.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.5...@ohif/viewer@1.5.0) (2019-10-09)
### Features
* Multiple fixes and implementation changes to react-cornerstone-viewport ([1cc94f3](https://github.com/OHIF/Viewers/commit/1cc94f3))
## [1.4.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.4...@ohif/viewer@1.4.5) (2019-10-09) ## [1.4.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.4...@ohif/viewer@1.4.5) (2019-10-09)
**Note:** Version bump only for package @ohif/viewer **Note:** Version bump only for package @ohif/viewer
@@ -1,47 +1,48 @@
describe('OHIF Study Viewer Page', () => { describe('OHIF Study Viewer Page', () => {
before(() => { before(() => {
cy.openStudy("MISTER^MR"); cy.openStudy('MISTER^MR');
}); cy.waitDicomImage();
});
it('checks if series thumbnails are being displayed', ()=> { it('checks if series thumbnails are being displayed', () => {
cy.get('.ThumbnailEntryContainer') cy.get('[data-cy="thumbnail-list"]')
.its('length') .its('length')
.should('be.gt', 1); .should('be.gt', 1);
});
it('drags and drop a series thumbnail into viewport', () => {
cy.get('.ThumbnailEntryContainer:nth-child(2)') //element to be dragged
.drag('.cornerstone-canvas'); //dropzone element
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-left.overlay-element > div';
const expectedText = 'Ser: 2Img: 1 1/13512 x 512Loc: -17.60 mm Thick: 3.00 mm';
cy.get(overlaySeriesInformation)
.should('have.text', expectedText);
});
it('checks if Series left panel can be hidden/displayed', ()=> {
const seriesButton = '.pull-left > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton';
const leftPanel = 'section.sidepanel.from-left';
cy.get(seriesButton).click();
cy.get(leftPanel).should('not.be.enabled')
cy.get(seriesButton).click();
cy.get(leftPanel).should('be.visible');
});
it('checks if Measurements right panel can be hidden/displayed', ()=> {
const measurementsButton = '.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton';
const rightPanel = 'section.sidepanel.from-right';
cy.get(measurementsButton).click();
cy.get(rightPanel).should('be.visible');
cy.get(measurementsButton).click();
cy.get(rightPanel).should('not.be.enabled');
});
}); });
it('drags and drop a series thumbnail into viewport', () => {
cy.get('[data-cy="thumbnail-list"]:nth-child(2)') //element to be dragged
.drag('.cornerstone-canvas'); //dropzone element
const overlaySeriesInformation =
'div.ViewportOverlay > div.bottom-left.overlay-element > div';
const expectedText =
'Ser: 2Img: 1 1/13512 x 512Loc: -17.60 mm Thick: 3.00 mm';
cy.get(overlaySeriesInformation).should('have.text', expectedText);
});
it('checks if Series left panel can be hidden/displayed', () => {
const seriesButton =
'.pull-left > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton';
const leftPanel = 'section.sidepanel.from-left';
cy.get(seriesButton).click();
cy.get(leftPanel).should('not.be.enabled');
cy.get(seriesButton).click();
cy.get(leftPanel).should('be.visible');
});
it('checks if Measurements right panel can be hidden/displayed', () => {
const measurementsButton =
'.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton';
const rightPanel = 'section.sidepanel.from-right';
cy.get(measurementsButton).click();
cy.get(rightPanel).should('be.visible');
cy.get(measurementsButton).click();
cy.get(rightPanel).should('not.be.enabled');
});
});
+64 -64
View File
@@ -1,6 +1,6 @@
import { DragSimulator } from "../helpers/DragSimulator.js"; import { DragSimulator } from '../helpers/DragSimulator.js';
import { doesNotReject } from "assert"; import { doesNotReject } from 'assert';
import { disconnect } from "cluster"; import { disconnect } from 'cluster';
// *********************************************** // ***********************************************
// This example commands.js shows you how to // This example commands.js shows you how to
@@ -28,21 +28,19 @@ import { disconnect } from "cluster";
// -- This is will overwrite an existing command -- // -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Cypress.Commands.add('openStudy', (patientName) => { Cypress.Commands.add('openStudy', patientName => {
cy.visit('/'); cy.visit('/');
cy.get('#patientName') cy.get('#patientName').type(patientName);
.type(patientName);
cy.get('.studylistStudy > .patientName').as('patientResult') cy.get('.studylistStudy > .patientName')
.then({ timeout: 5000 }, ($patientResult) => { .as('patientResult')
cy.contains(patientName) .then({ timeout: 5000 }, $patientResult => {
.click(); cy.contains(patientName).click();
}) });
} });
);
Cypress.Commands.add('drag', {prevSubject: 'element',}, Cypress.Commands.add('drag', { prevSubject: 'element' }, (...args) =>
(...args) => DragSimulator.simulate(...args) DragSimulator.simulate(...args)
); );
/** /**
@@ -53,20 +51,18 @@ Cypress.Commands.add('drag', {prevSubject: 'element',},
* @param {number[]} firstClick - Click position [x, y] * @param {number[]} firstClick - Click position [x, y]
* @param {number[]} secondClick - Click position [x, y] * @param {number[]} secondClick - Click position [x, y]
*/ */
Cypress.Commands.add('addLine', (viewport, firstClick, secondClick) => { Cypress.Commands.add('addLine', (viewport, firstClick, secondClick) => {
cy.get(viewport).then($viewport => {
cy.get(viewport).then(($viewport) => { const [x1, y1] = firstClick;
const [ x1, y1 ] = firstClick; const [x2, y2] = secondClick;
const [ x2, y2 ] = secondClick;
cy.wrap($viewport) cy.wrap($viewport)
.click(x1, y1, {force: true}) .click(x1, y1, { force: true })
.trigger('mousemove', {clientX:x2, clientY:y2}) .trigger('mousemove', { clientX: x2, clientY: y2 })
.click(x2, y2, {force: true}) .click(x2, y2, { force: true });
}); });
}); });
/** /**
* Command to perform three clicks into three different positions. Each position must be [x, y]. * Command to perform three clicks into three different positions. Each position must be [x, y].
* The positions are considering the element as reference, therefore, top-left of the element will be (0, 0). * The positions are considering the element as reference, therefore, top-left of the element will be (0, 0).
@@ -76,62 +72,66 @@ Cypress.Commands.add('addLine', (viewport, firstClick, secondClick) => {
* @param {number[]} secondClick - Click position [x, y] * @param {number[]} secondClick - Click position [x, y]
* @param {number[]} thirdClick - Click position [x, y] * @param {number[]} thirdClick - Click position [x, y]
*/ */
Cypress.Commands.add('addAngle', (viewport, firstClick, secondClick, thirdClick) => { Cypress.Commands.add(
'addAngle',
cy.get(viewport).then(($viewport) => { (viewport, firstClick, secondClick, thirdClick) => {
const [ x1, y1 ] = firstClick; cy.get(viewport).then($viewport => {
const [ x2, y2 ] = secondClick; const [x1, y1] = firstClick;
const [ x3, y3 ] = thirdClick; const [x2, y2] = secondClick;
const [x3, y3] = thirdClick;
cy.wrap($viewport)
.click(x1, y1, {force: true})
.trigger('mousemove', {clientX:x2, clientY:y2})
.click(x2, y2, {force: true})
.trigger('mousemove', {clientX:x3, clientY:y3})
.click(x3, y3, {force: true})
});
});
cy.wrap($viewport)
.click(x1, y1, { force: true })
.trigger('mousemove', { clientX: x2, clientY: y2 })
.click(x2, y2, { force: true })
.trigger('mousemove', { clientX: x3, clientY: y3 })
.click(x3, y3, { force: true });
});
}
);
//Command to wait DICOM image to load into the viewport //Command to wait DICOM image to load into the viewport
Cypress.Commands.add('waitDicomImage', (timeout = 10000) => { Cypress.Commands.add('waitDicomImage', (timeout = 20000) => {
cy.window() cy.window()
.its('cornerstone') .its('cornerstone')
.then($cornerstone => { .then({ timeout }, $cornerstone => {
return new Cypress.Promise(resolve => { return new Cypress.Promise(resolve => {
const onEvent = (renderedEvt) => { const onEvent = renderedEvt => {
const element = renderedEvt.detail.element; const element = renderedEvt.detail.element;
element.removeEventListener('cornerstoneimagerendered', onEvent); element.removeEventListener('cornerstoneimagerendered', onEvent);
$cornerstone.events.removeEventListener('cornerstoneimagerendered', onEvent); $cornerstone.events.removeEventListener(
resolve(); 'cornerstoneimagerendered',
} onEvent
const onEnabled = (enabledEvt) => { );
const element = enabledEvt.detail.element; resolve();
};
const onEnabled = enabledEvt => {
const element = enabledEvt.detail.element;
element.addEventListener('cornerstoneimagerendered', onEvent); element.addEventListener('cornerstoneimagerendered', onEvent);
} };
$cornerstone.events.addEventListener('cornerstoneelementenabled', onEnabled); $cornerstone.events.addEventListener(
'cornerstoneelementenabled',
onEnabled
);
});
}); });
});
}); });
//Command to reset the viewport changes throught the cornerstone method //Command to reset the viewport changes throught the cornerstone method
Cypress.Commands.add('resetViewport', () => { Cypress.Commands.add('resetViewport', () => {
cy.get('@resetBtn').click() cy.get('@resetBtn').click();
}); });
Cypress.Commands.add('imageZoomIn', () => { Cypress.Commands.add('imageZoomIn', () => {
cy.get('@zoomBtn').click(); cy.get('@zoomBtn').click();
//drags the mouse inside the viewport to be able to interact with series //drags the mouse inside the viewport to be able to interact with series
cy.get('@viewport') cy.get('@viewport')
.trigger('mousedown', 'top', { which: 1 }) .trigger('mousedown', 'top', { which: 1 })
.trigger('mousemove', 'center', { which: 1 }) .trigger('mousemove', 'center', { which: 1 })
.trigger('mouseup'); .trigger('mouseup');
}); });
Cypress.Commands.add('imageContrast', () => { Cypress.Commands.add('imageContrast', () => {
@@ -139,7 +139,7 @@ Cypress.Commands.add('imageContrast', () => {
//drags the mouse inside the viewport to be able to interact with series //drags the mouse inside the viewport to be able to interact with series
cy.get('@viewport') cy.get('@viewport')
.trigger('mousedown', 'center', { which: 1 }) .trigger('mousedown', 'center', { which: 1 })
.trigger('mousemove', 'top', { which: 1 }) .trigger('mousemove', 'top', { which: 1 })
.trigger('mouseup'); .trigger('mouseup');
}); });
+5 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/viewer", "name": "@ohif/viewer",
"version": "1.4.5", "version": "1.5.2",
"description": "OHIF Viewer", "description": "OHIF Viewer",
"author": "OHIF Contributors", "author": "OHIF Contributors",
"license": "MIT", "license": "MIT",
@@ -20,8 +20,8 @@
"build:package": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.commonjs.js", "build:package": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.commonjs.js",
"build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress", "build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress",
"build:viewer:e2e": "cross-env NODE_ENV=development node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress", "build:viewer:e2e": "cross-env NODE_ENV=development node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress",
"build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js", "build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js SKIP_MINIMIZE=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js",
"build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js", "build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html SKIP_MINIMIZE=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js",
"build:viewer:package": "yarn run build:package", "build:viewer:package": "yarn run build:package",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config .webpack/webpack.pwa.js --watch", "dev": "cross-env NODE_ENV=development webpack-dev-server --config .webpack/webpack.pwa.js --watch",
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js --watch", "dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js --watch",
@@ -51,9 +51,9 @@
"@ohif/extension-dicom-html": "^1.0.0", "@ohif/extension-dicom-html": "^1.0.0",
"@ohif/extension-dicom-microscopy": "^0.50.6", "@ohif/extension-dicom-microscopy": "^0.50.6",
"@ohif/extension-dicom-pdf": "^1.0.0", "@ohif/extension-dicom-pdf": "^1.0.0",
"@ohif/extension-vtk": "^0.52.2", "@ohif/extension-vtk": "^0.52.4",
"@ohif/i18n": "^0.50.5", "@ohif/i18n": "^0.50.5",
"@ohif/ui": "^0.53.1", "@ohif/ui": "^0.53.3",
"@tanem/react-nprogress": "^1.1.25", "@tanem/react-nprogress": "^1.1.25",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"core-js": "^3.2.1", "core-js": "^3.2.1",
@@ -1,41 +1,35 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" /> <head>
<!-- Built with: https://polyfill.io/v3/url-builder/ --> <meta charset="utf-8" />
<!-- Targets IE11 --> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<script src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script> <meta name="theme-color" content="#000000" />
<script
type="text/javascript"
src="<%= PUBLIC_URL %>app-config.js"
></script>
<title>OHIF Viewer</title> <link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" />
<!-- Built with: https://polyfill.io/v3/url-builder/ -->
<!-- Targets IE11 -->
<script
src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script>
<script type="text/javascript" src="<%= PUBLIC_URL %>app-config.js"></script>
<!-- WEB FONTS --> <title>OHIF Viewer</title>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap"
rel="stylesheet"
/>
<!-- EXTENSIONS --> <!-- WEB FONTS -->
<!-- <script type="text/javascript" src="path/to/some-extension.js"></script> <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700&display=swap" rel="stylesheet" />
<!-- EXTENSIONS -->
<!-- <script type="text/javascript" src="path/to/some-extension.js"></script>
<script> <script>
window.config.extensions = [SomeExtension]; window.config.extensions = [SomeExtension];
</script> --> </script> -->
</head> </head>
<body> <body>
<noscript> You need to enable JavaScript to run this app. </noscript> <noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
</body>
<div id="root"></div>
</body>
</html> </html>
@@ -1,53 +1,50 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" /> <head>
<!-- Built with: https://polyfill.io/v3/url-builder/ --> <meta charset="utf-8" />
<!-- Targets IE11 --> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<script src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script> <meta name="theme-color" content="#000000" />
<script type="text/javascript" src="<%= PUBLIC_URL %>app-config.js"></script>
<title>OHIF Viewer</title> <link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" />
<!-- Built with: https://polyfill.io/v3/url-builder/ -->
<!-- Targets IE11 -->
<script
src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script>
<script type="text/javascript" src="<%= PUBLIC_URL %>app-config.js"></script>
<!-- WEB FONTS --> <title>OHIF Viewer</title>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap"
rel="stylesheet"
/>
<!-- EXTENSIONS --> <!-- WEB FONTS -->
<!-- <script type="text/javascript" src="path/to/some-extension.js"></script> <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700&display=swap" rel="stylesheet" />
<!-- EXTENSIONS -->
<!-- <script type="text/javascript" src="path/to/some-extension.js"></script>
<script> <script>
window.config.extensions = [SomeExtension]; window.config.extensions = [SomeExtension];
</script> --> </script> -->
</head> </head>
<body> <body>
<noscript> You need to enable JavaScript to run this app. </noscript> <noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div> <div id="root"></div>
<script> <script>
// Note: This is a client access token so there is no issue with having it publicly available // Note: This is a client access token so there is no issue with having it publicly available
var _rollbarConfig = { var _rollbarConfig = {
accessToken: "739c64cd39e84592ba062bc29aac9769", accessToken: "739c64cd39e84592ba062bc29aac9769",
captureUncaught: true, captureUncaught: true,
captureUnhandledRejections: true, captureUnhandledRejections: true,
payload: { payload: {
environment: "viewer.ohif.org" environment: "viewer.ohif.org"
} }
}; };
// Rollbar Snippet // Rollbar Snippet
!function(r){var e={};function o(n){if(e[n])return e[n].exports;var t=e[n]={i:n,l:!1,exports:{}};return r[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=e,o.d=function(r,e,n){o.o(r,e)||Object.defineProperty(r,e,{enumerable:!0,get:n})},o.r=function(r){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},o.t=function(r,e){if(1&e&&(r=o(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var t in r)o.d(n,t,function(e){return r[e]}.bind(null,t));return n},o.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return o.d(e,"a",e),e},o.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},o.p="",o(o.s=0)}([function(r,e,o){var n=o(1),t=o(4);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.7.1/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,e,o){var n=o(2);function t(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}var a=0;function l(r,e){this.options=r,this._rollbarOldOnError=null;var o=a++;this.shimId=function(){return o},"undefined"!=typeof window&&window._rollbarShims&&(window._rollbarShims[o]={handler:e,messages:[]})}var i=o(3),d=function(r,e){return new l(r,e)},c=function(r){return new i(d,r)};function s(r){return t(function(){var e=Array.prototype.slice.call(arguments,0),o={shim:this,method:r,args:e,ts:new Date};window._rollbarShims[this.shimId()].messages.push(o)})}l.prototype.loadFull=function(r,e,o,n,a){var l=!1,i=e.createElement("script"),d=e.getElementsByTagName("script")[0],c=d.parentNode;i.crossOrigin="",i.src=n.rollbarJsUrl,o||(i.async=!0),i.onload=i.onreadystatechange=t(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){i.onload=i.onreadystatechange=null;try{c.removeChild(i)}catch(r){}l=!0,function(){var e;if(void 0===r._rollbarDidLoad){e=new Error("rollbar.js did not load");for(var o,n,t,l,i=0;o=r._rollbarShims[i++];)for(o=o.messages||[];n=o.shift();)for(t=n.args||[],i=0;i<t.length;++i)if("function"==typeof(l=t[i])){l(e);break}}"function"==typeof a&&a(e)}()}}),c.insertBefore(i,d)},l.prototype.wrap=function(r,e,o){try{var n;if(n="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){o&&"function"==typeof o&&o.apply(this,arguments);try{return r.apply(this,arguments)}catch(o){var e=o;throw e&&("string"==typeof e&&(e=new String(e)),e._rollbarContext=n()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e),e}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(e){return r}};for(var p="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),u=0;u<p.length;++u)l.prototype[p[u]]=s(p[u]);r.exports={setupShim:function(r,e){if(r){var o=e.globalAlias||"Rollbar";if("object"==typeof r[o])return r[o];r._rollbarShims={},r._rollbarWrappedError=null;var a=new c(e);return t(function(){e.captureUncaught&&(a._rollbarOldOnError=r.onerror,n.captureUncaughtExceptions(r,a,!0),n.wrapGlobals(r,a,!0)),e.captureUnhandledRejections&&n.captureUnhandledRejections(r,a,!0);var t=e.autoInstrument;return!1!==e.enabled&&(void 0===t||!0===t||"object"==typeof t&&t.network)&&r.addEventListener&&(r.addEventListener("load",a.captureLoad.bind(a)),r.addEventListener("DOMContentLoaded",a.captureDomContentLoaded.bind(a))),r[o]=a,a})()}},Rollbar:c}},function(r,e){function o(r,e,o){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){for(var n=e.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(e,o,t){n.call(this,e,r.wrap(o),t)};t._rollbarOldAdd=n,t.belongsToShim=o,e.addEventListener=t;for(var a=e.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,e,o){a.call(this,r,e&&e._rollbar_wrapped||e,o)};l._rollbarOldRemove=a,l.belongsToShim=o,e.removeEventListener=l}}r.exports={captureUncaughtExceptions:function(r,e,o){if(r){var n;if("function"==typeof e._rollbarOldOnError)n=e._rollbarOldOnError;else if(r.onerror){for(n=r.onerror;n._rollbarOldOnError;)n=n._rollbarOldOnError;e._rollbarOldOnError=n}var t=function(){var o=Array.prototype.slice.call(arguments,0);!function(r,e,o,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._roLine truncated !function (r) { var e = {}; function o(n) { if (e[n]) return e[n].exports; var t = e[n] = { i: n, l: !1, exports: {} }; return r[n].call(t.exports, t, t.exports, o), t.l = !0, t.exports } o.m = r, o.c = e, o.d = function (r, e, n) { o.o(r, e) || Object.defineProperty(r, e, { enumerable: !0, get: n }) }, o.r = function (r) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(r, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(r, "__esModule", { value: !0 }) }, o.t = function (r, e) { if (1 & e && (r = o(r)), 8 & e) return r; if (4 & e && "object" == typeof r && r && r.__esModule) return r; var n = Object.create(null); if (o.r(n), Object.defineProperty(n, "default", { enumerable: !0, value: r }), 2 & e && "string" != typeof r) for (var t in r) o.d(n, t, function (e) { return r[e] }.bind(null, t)); return n }, o.n = function (r) { var e = r && r.__esModule ? function () { return r.default } : function () { return r }; return o.d(e, "a", e), e }, o.o = function (r, e) { return Object.prototype.hasOwnProperty.call(r, e) }, o.p = "", o(o.s = 0) }([function (r, e, o) { var n = o(1), t = o(4); _rollbarConfig = _rollbarConfig || {}, _rollbarConfig.rollbarJsUrl = _rollbarConfig.rollbarJsUrl || "https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.7.1/rollbar.min.js", _rollbarConfig.async = void 0 === _rollbarConfig.async || _rollbarConfig.async; var a = n.setupShim(window, _rollbarConfig), l = t(_rollbarConfig); window.rollbar = n.Rollbar, a.loadFull(window, document, !_rollbarConfig.async, _rollbarConfig, l) }, function (r, e, o) { var n = o(2); function t(r) { return function () { try { return r.apply(this, arguments) } catch (r) { try { console.error("[Rollbar]: Internal error", r) } catch (r) { } } } } var a = 0; function l(r, e) { this.options = r, this._rollbarOldOnError = null; var o = a++; this.shimId = function () { return o }, "undefined" != typeof window && window._rollbarShims && (window._rollbarShims[o] = { handler: e, messages: [] }) } var i = o(3), d = function (r, e) { return new l(r, e) }, c = function (r) { return new i(d, r) }; function s(r) { return t(function () { var e = Array.prototype.slice.call(arguments, 0), o = { shim: this, method: r, args: e, ts: new Date }; window._rollbarShims[this.shimId()].messages.push(o) }) } l.prototype.loadFull = function (r, e, o, n, a) { var l = !1, i = e.createElement("script"), d = e.getElementsByTagName("script")[0], c = d.parentNode; i.crossOrigin = "", i.src = n.rollbarJsUrl, o || (i.async = !0), i.onload = i.onreadystatechange = t(function () { if (!(l || this.readyState && "loaded" !== this.readyState && "complete" !== this.readyState)) { i.onload = i.onreadystatechange = null; try { c.removeChild(i) } catch (r) { } l = !0, function () { var e; if (void 0 === r._rollbarDidLoad) { e = new Error("rollbar.js did not load"); for (var o, n, t, l, i = 0; o = r._rollbarShims[i++];)for (o = o.messages || []; n = o.shift();)for (t = n.args || [], i = 0; i < t.length; ++i)if ("function" == typeof (l = t[i])) { l(e); break } } "function" == typeof a && a(e) }() } }), c.insertBefore(i, d) }, l.prototype.wrap = function (r, e, o) { try { var n; if (n = "function" == typeof e ? e : function () { return e || {} }, "function" != typeof r) return r; if (r._isWrap) return r; if (!r._rollbar_wrapped && (r._rollbar_wrapped = function () { o && "function" == typeof o && o.apply(this, arguments); try { return r.apply(this, arguments) } catch (o) { var e = o; throw e && ("string" == typeof e && (e = new String(e)), e._rollbarContext = n() || {}, e._rollbarContext._wrappedSource = r.toString(), window._rollbarWrappedError = e), e } }, r._rollbar_wrapped._isWrap = !0, r.hasOwnProperty)) for (var t in r) r.hasOwnProperty(t) && (r._rollbar_wrapped[t] = r[t]); return r._rollbar_wrapped } catch (e) { return r } }; for (var p = "log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","), u = 0; u < p.length; ++u)l.prototype[p[u]] = s(p[u]); r.exports = { setupShim: function (r, e) { if (r) { var o = e.globalAlias || "Rollbar"; if ("object" == typeof r[o]) return r[o]; r._rollbarShims = {}, r._rollbarWrappedError = null; var a = new c(e); return t(function () { e.captureUncaught && (a._rollbarOldOnError = r.onerror, n.captureUncaughtExceptions(r, a, !0), n.wrapGlobals(r, a, !0)), e.captureUnhandledRejections && n.captureUnhandledRejections(r, a, !0); var t = e.autoInstrument; return !1 !== e.enabled && (void 0 === t || !0 === t || "object" == typeof t && t.network) && r.addEventListener && (r.addEventListener("load", a.captureLoad.bind(a)), r.addEventListener("DOMContentLoaded", a.captureDomContentLoaded.bind(a))), r[o] = a, a })() } }, Rollbar: c } }, function (r, e) { function o(r, e, o) { if (e.hasOwnProperty && e.hasOwnProperty("addEventListener")) { for (var n = e.addEventListener; n._rollbarOldAdd && n.belongsToShim;)n = n._rolLine truncated
// End Rollbar Snippet // End Rollbar Snippet
</script> </script>
</body> </body>
</html> </html>
@@ -1,67 +1,59 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta <head>
name="description" <meta charset="utf-8" />
content="Open Health Imaging Foundation DICOM Viewer"
/>
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no"
/>
<meta name="theme-color" content="#000000" />
<meta http-equiv="cleartype" content="on" />
<meta name="MobileOptimized" content="320" />
<meta name="HandheldFriendly" content="True" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<script src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script> <meta name="description" content="Open Health Imaging Foundation DICOM Viewer" />
<meta name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta name="theme-color" content="#000000" />
<meta http-equiv="cleartype" content="on" />
<meta name="MobileOptimized" content="320" />
<meta name="HandheldFriendly" content="True" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- WEB FONTS --> <script
<link src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CObject.values%2CArray.prototype.flat%2CObject.entries%2CSymbol%2CArray.prototype.includes%2CString.prototype.repeat%2CArray.prototype.find"></script>
href="https://fonts.googleapis.com/css?family=Sanchez"
rel="stylesheet"
/>
<title>OHIF Standalone Viewer</title> <title>OHIF Standalone Viewer</title>
</head> </head>
<body> <body>
<noscript> You need to enable JavaScript to run this app. </noscript> <noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div> <div id="root"></div>
<script src="/index.umd.js" crossorigin></script> <script src="/index.umd.js" crossorigin></script>
<script> <script>
var containerId = 'root'; var containerId = 'root';
var componentRenderedOrUpdatedCallback = function() { var componentRenderedOrUpdatedCallback = function () {
console.log('OHIF Viewer rendered/updated'); console.log('OHIF Viewer rendered/updated');
}; };
window.OHIFViewer.installViewer( window.OHIFViewer.installViewer(
{ {
// routerBasename: '/', // routerBasename: '/',
servers: { servers: {
dicomWeb: [ dicomWeb: [
{ {
name: 'DCM4CHEE', name: 'DCM4CHEE',
wadoUriRoot: wadoUriRoot:
'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado', 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: qidoRoot:
'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs', 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: wadoRoot:
'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs', 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true, qidoSupportsIncludeField: true,
imageRendering: 'wadors', imageRendering: 'wadors',
thumbnailRendering: 'wadors', thumbnailRendering: 'wadors',
}, },
], ],
},
}, },
containerId, },
componentRenderedOrUpdatedCallback containerId,
); componentRenderedOrUpdatedCallback
</script> );
</body> </script>
</body>
</html> </html>
+2 -11
View File
@@ -15,7 +15,6 @@ import {
} from './utils/index.js'; } from './utils/index.js';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
import initCornerstoneTools from './initCornerstoneTools.js';
// ~~ EXTENSIONS // ~~ EXTENSIONS
import { GenericViewerCommands, MeasurementsPanel } from './appExtensions'; import { GenericViewerCommands, MeasurementsPanel } from './appExtensions';
@@ -27,7 +26,6 @@ import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import { getActiveContexts } from './store/layout/selectors.js'; import { getActiveContexts } from './store/layout/selectors.js';
import i18n from '@ohif/i18n'; import i18n from '@ohif/i18n';
import setupTools from './setupTools.js';
import store from './store'; import store from './store';
// Contexts // Contexts
@@ -36,11 +34,6 @@ import UserManagerContext from './context/UserManagerContext';
import AppContext from './context/AppContext'; import AppContext from './context/AppContext';
// ~~~~ APP SETUP // ~~~~ APP SETUP
initCornerstoneTools({
globalToolSyncEnabled: true,
showSVGCursors: true,
});
const commandsManagerConfig = { const commandsManagerConfig = {
getAppState: () => store.getState(), getAppState: () => store.getState(),
getActiveContexts: () => getActiveContexts(store.getState()), getActiveContexts: () => getActiveContexts(store.getState()),
@@ -49,9 +42,6 @@ const commandsManagerConfig = {
const commandsManager = new CommandsManager(commandsManagerConfig); const commandsManager = new CommandsManager(commandsManagerConfig);
const hotkeysManager = new HotkeysManager(commandsManager); const hotkeysManager = new HotkeysManager(commandsManager);
const extensionManager = new ExtensionManager({ commandsManager }); const extensionManager = new ExtensionManager({ commandsManager });
// CornerstoneTools and labeling/measurements?
setupTools(store);
// ~~~~ END APP SETUP // ~~~~ END APP SETUP
// TODO[react] Use a provider when the whole tree is React // TODO[react] Use a provider when the whole tree is React
@@ -175,8 +165,9 @@ class App extends Component {
function _initExtensions(extensions, hotkeys) { function _initExtensions(extensions, hotkeys) {
const defaultExtensions = [ const defaultExtensions = [
GenericViewerCommands, GenericViewerCommands,
MeasurementsPanel,
OHIFCornerstoneExtension, OHIFCornerstoneExtension,
// WARNING: MUST BE REGISTERED _AFTER_ OHIFCORNERSTONEEXTENSION
MeasurementsPanel,
]; ];
const mergedExtensions = defaultExtensions.concat(extensions); const mergedExtensions = defaultExtensions.concat(extensions);
extensionManager.registerExtensions(mergedExtensions); extensionManager.registerExtensions(mergedExtensions);
@@ -6,7 +6,7 @@ import cornerstone from 'cornerstone-core';
// //
import jumpToRowItem from './jumpToRowItem.js'; import jumpToRowItem from './jumpToRowItem.js';
import getMeasurementLocationCallback from './../../lib/getMeasurementLocationCallback'; import getMeasurementLocationCallback from './getMeasurementLocationCallback';
const { setViewportSpecificData } = OHIF.redux.actions; const { setViewportSpecificData } = OHIF.redux.actions;
const { MeasurementApi } = OHIF.measurements; const { MeasurementApi } = OHIF.measurements;
@@ -0,0 +1,21 @@
const setLabellingFlowDataAction = labellingFlowData => ({
type: 'SET_LABELLING_FLOW_DATA',
labellingFlowData,
});
const resetLabellingAndContextMenuAction = state => ({
type: 'RESET_LABELLING_AND_CONTEXT_MENU',
state,
});
const setToolContextMenuDataAction = (viewportIndex, toolContextMenuData) => ({
type: 'SET_TOOL_CONTEXT_MENU_DATA',
viewportIndex,
toolContextMenuData,
});
export {
resetLabellingAndContextMenuAction,
setLabellingFlowDataAction,
setToolContextMenuDataAction,
};
@@ -1,5 +1,5 @@
import cornerstoneTools from 'cornerstone-tools'; import cornerstoneTools from 'cornerstone-tools';
import updateTableWithNewMeasurementData from './updateTableWithNewMeasurementData'; import updateTableWithNewMeasurementData from './updateTableWithNewMeasurementData.js';
export default function getMeasurementLocationCallback( export default function getMeasurementLocationCallback(
eventData, eventData,
@@ -1,7 +1,15 @@
import ConnectedMeasurementTable from './ConnectedMeasurementTable.js'; import ConnectedMeasurementTable from './ConnectedMeasurementTable.js';
import init from './init.js';
export default { export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'measurements-table', id: 'measurements-table',
preRegistration(configuration = {}) {
init(configuration);
},
getPanelModule() { getPanelModule() {
return { return {
menuOptions: [ menuOptions: [
@@ -0,0 +1,188 @@
import OHIF from '@ohif/core';
import cornerstone from 'cornerstone-core';
import csTools from 'cornerstone-tools';
import {
getToolLabellingFlowCallback,
getOnRightClickCallback,
getOnTouchPressCallback,
getResetLabellingAndContextMenu,
} from './labelingFlowCallbacks.js';
import throttle from 'lodash.throttle';
// TODO: This only works because we have a hard dependency on this extension
// We need to decouple and make stuff like this possible w/o bundling this at
// build time
import store from './../../store';
const {
onAdded,
onRemoved,
onModified,
} = OHIF.measurements.MeasurementHandlers;
const MEASUREMENT_ACTION_MAP = {
added: onAdded,
removed: onRemoved,
modified: throttle(event => {
return onModified(event);
}, 300),
};
/**
*
*
* @export
* @param {*} configuration
*/
export default function init(configuration) {
// If these tools were already added by a different extension, we want to replace
// them with the same tools that have an alternative configuration. By passing in
// our custom `getMeasurementLocationCallback`, we can...
const toolLabellingFlowCallback = getToolLabellingFlowCallback(store);
// Removes all tools from all enabled elements w/ provided name
// Not commonly used API, so :eyes: for unknown side-effects
csTools.removeTool('Bidirectional');
csTools.removeTool('Length');
csTools.removeTool('Angle');
csTools.removeTool('FreehandRoi');
csTools.removeTool('EllipticalRoi');
csTools.removeTool('CircleRoi');
csTools.removeTool('RectangleRoi');
csTools.removeTool('ArrowAnnotate');
// Re-add each tool w/ our custom configuration
csTools.addTool(csTools.BidirectionalTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.LengthTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.AngleTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.FreehandRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.EllipticalRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.CircleRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.RectangleRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.ArrowAnnotateTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
// TODO: MEASUREMENT_COMPLETED (not present in initial implementation)
const onMeasurementsChanged = (action, event) => {
return MEASUREMENT_ACTION_MAP[action](event);
};
const onMeasurementAdded = onMeasurementsChanged.bind(this, 'added');
const onMeasurementRemoved = onMeasurementsChanged.bind(this, 'removed');
const onMeasurementModified = onMeasurementsChanged.bind(this, 'modified');
const onLabelmapModified = onMeasurementsChanged.bind(
this,
'labelmapModified'
);
//
const onRightClick = getOnRightClickCallback(store);
const onTouchPress = getOnTouchPressCallback(store);
const onNewImage = getResetLabellingAndContextMenu(store);
const onMouseClick = getResetLabellingAndContextMenu(store);
const onTouchStart = getResetLabellingAndContextMenu(store);
// Because click gives us the native "mouse up", buttons will always be `0`
// Need to fallback to event.which;
const handleClick = cornerstoneMouseClickEvent => {
const mouseUpEvent = cornerstoneMouseClickEvent.detail.event;
const isRightClick = mouseUpEvent.which === 3;
if (isRightClick) {
onRightClick(cornerstoneMouseClickEvent);
} else {
onMouseClick(cornerstoneMouseClickEvent);
}
};
function elementEnabledHandler(evt) {
const element = evt.detail.element;
element.addEventListener(
csTools.EVENTS.MEASUREMENT_ADDED,
onMeasurementAdded
);
element.addEventListener(
csTools.EVENTS.MEASUREMENT_REMOVED,
onMeasurementRemoved
);
element.addEventListener(
csTools.EVENTS.MEASUREMENT_MODIFIED,
onMeasurementModified
);
element.addEventListener(
csTools.EVENTS.LABELMAP_MODIFIED,
onLabelmapModified
);
//
element.addEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
element.addEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
element.addEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
// TODO: This makes scrolling painfully slow
// element.addEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
}
function elementDisabledHandler(evt) {
const element = evt.detail.element;
element.removeEventListener(
csTools.EVENTS.MEASUREMENT_ADDED,
onMeasurementAdded
);
element.removeEventListener(
csTools.EVENTS.MEASUREMENT_REMOVED,
onMeasurementRemoved
);
element.removeEventListener(
csTools.EVENTS.MEASUREMENT_MODIFIED,
onMeasurementModified
);
element.removeEventListener(
csTools.EVENTS.LABELMAP_MODIFIED,
onLabelmapModified
);
//
element.removeEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
element.removeEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
element.removeEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
// element.removeEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
}
cornerstone.events.addEventListener(
cornerstone.EVENTS.ELEMENT_ENABLED,
elementEnabledHandler
);
cornerstone.events.addEventListener(
cornerstone.EVENTS.ELEMENT_DISABLED,
elementDisabledHandler
);
}
@@ -0,0 +1,144 @@
import {
resetLabellingAndContextMenuAction,
setToolContextMenuDataAction,
setLabellingFlowDataAction,
} from './actions.js';
import updateTableWithNewMeasurementData from './updateTableWithNewMeasurementData.js';
const VIEWPORT_INDEX = 0;
function getOnRightClickCallback(store) {
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
store.dispatch(resetLabellingAndContextMenuAction());
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
const getOnCloseCallback = viewportIndex => {
return function onClose() {
const toolContextMenuData = {
visible: false,
};
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
};
return function onRightClick(event) {
const eventData = event.detail;
const viewportIndex = VIEWPORT_INDEX; // parseInt(eventData.element.dataset.viewportIndex, 10);
const toolContextMenuData = {
eventData,
isTouchEvent: false,
onClose: getOnCloseCallback(viewportIndex),
};
// setToolContextMenuData(viewportIndex, toolContextMenuData);
setToolContextMenuData(0, toolContextMenuData);
};
}
function getOnTouchPressCallback(store) {
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
store.dispatch(resetLabellingAndContextMenuAction());
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
const getOnCloseCallback = viewportIndex => {
return function onClose() {
const toolContextMenuData = {
visible: false,
};
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
};
return function onTouchPress(event) {
const eventData = event.detail;
const viewportIndex = parseInt(eventData.element.dataset.viewportIndex, 10);
const toolContextMenuData = {
eventData,
isTouchEvent: true,
onClose: getOnCloseCallback(viewportIndex),
};
setToolContextMenuData(viewportIndex, toolContextMenuData);
};
}
function getResetLabellingAndContextMenu(store) {
return function resetLabellingAndContextMenu() {
store.dispatch(resetLabellingAndContextMenuAction());
};
}
/**
*
*
* @param {*} store
* @returns
*/
function getToolLabellingFlowCallback(store) {
const setLabellingFlowData = labellingFlowData => {
store.dispatch(setLabellingFlowDataAction(labellingFlowData));
};
return function toolLabellingFlowCallback(
measurementData,
eventData,
doneCallback,
options = {}
) {
const updateLabelling = ({ location, response, description }) => {
// Update the measurement data with the labelling parameters
if (location) {
measurementData.location = location;
}
if (description) {
measurementData.description = description;
}
if (response) {
measurementData.response = response;
}
updateTableWithNewMeasurementData(measurementData);
};
const labellingDoneCallback = () => {
setLabellingFlowData({ visible: false });
};
const labellingFlowData = {
visible: true,
eventData,
measurementData,
skipAddLabelButton: options.skipAddLabelButton,
editLocation: options.editLocation,
editDescription: options.editDescription,
editResponse: options.editResponse,
editDescriptionOnDialog: options.editDescriptionOnDialog,
labellingDoneCallback,
updateLabelling,
};
setLabellingFlowData(labellingFlowData);
};
}
export {
getToolLabellingFlowCallback,
getOnRightClickCallback,
getOnTouchPressCallback,
getResetLabellingAndContextMenu,
};
@@ -1,11 +1,11 @@
import OHIF from "@ohif/core"; import OHIF from '@ohif/core';
import cornerstone from "cornerstone-core"; import cornerstone from 'cornerstone-core';
export default function updateTableWithNewMeasurementData({ export default function updateTableWithNewMeasurementData({
toolType, toolType,
measurementNumber, measurementNumber,
location, location,
description description,
}) { }) {
// Update all measurements by measurement number // Update all measurements by measurement number
const measurementApi = OHIF.measurements.MeasurementApi.Instance; const measurementApi = OHIF.measurements.MeasurementApi.Instance;
@@ -4,7 +4,7 @@
} }
.entry-header.header-big { .entry-header.header-big {
background: rgba(21,25,30,0.7); background: rgba(21, 25, 30, 0.7);
padding: 10px var(--study-list-padding); padding: 10px var(--study-list-padding);
height: auto; height: auto;
display: inline-block; display: inline-block;
@@ -32,7 +32,6 @@
padding: 25px 0; padding: 25px 0;
} }
.header-logo-image { .header-logo-image {
fill: transparent; fill: transparent;
height: 100%; height: 100%;
@@ -47,18 +46,9 @@
height: 50px; height: 50px;
} }
.header-logo-text {
display: inline-block;
font-family: var(--logo-font-family);
font-size: 14px;
font-weight: var(--logo-font-weight);
color: var(--text-primary-color);
line-height: 30px;
}
.entry-header.header-big .header-logo-text { .entry-header.header-big .header-logo-text {
font-size: 30px; width: 474px;
line-height: 36px; height: auto;
} }
.header-btn { .header-btn {
@@ -2,23 +2,19 @@
height: 30px; height: 30px;
text-decoration: none; text-decoration: none;
text-decoration-color: none; text-decoration-color: none;
display: flex; display: flex;
align-items: center;
color: var(--text-primary-color); color: var(--text-primary-color);
font-size: 14px;
font-weight: var(--logo-font-weight);
font-family: var(--logo-font-family);
} }
.header-brand:hover, .header-brand:hover, .header-brand:active, .header-band:visited {
.header-brand:active,
.header-band:visited {
color: var(--text-primary-color); color: var(--text-primary-color);
text-decoration: none; text-decoration: none;
} }
.header-logo-text { .header-logo-text {
line-height: 30px; width: 224px;
height: auto;
margin-left: 8px; margin-left: 8px;
} }
@@ -12,7 +12,7 @@ function OHIFLogo() {
href="http://ohif.org" href="http://ohif.org"
> >
<Icon name="ohif-logo" className="header-logo-image" /> <Icon name="ohif-logo" className="header-logo-image" />
<div className="header-logo-text">Open Health Imaging Foundation</div> <Icon name="ohif-text-logo" className="header-logo-text" />
</a> </a>
); );
} }
@@ -2,18 +2,19 @@ import { LayoutButton } from '@ohif/ui';
import OHIF from '@ohif/core'; import OHIF from '@ohif/core';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
const { setLayout } = OHIF.redux.actions; const { setLayout, setViewportActive } = OHIF.redux.actions;
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
currentLayout: state.viewports.layout, currentLayout: state.viewports.layout,
activeViewportIndex: state.viewports.activeViewportIndex
}; };
}; };
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
// TODO: Change if layout switched becomes more complex // TODO: Change if layout switched becomes more complex
onChange: (selectedCell, currentLayout) => { onChange: (selectedCell, currentLayout, activeViewportIndex) => {
let viewports = []; let viewports = [];
const rows = selectedCell.row + 1; const rows = selectedCell.row + 1;
const columns = selectedCell.col + 1; const columns = selectedCell.col + 1;
@@ -36,6 +37,11 @@ const mapDispatchToProps = dispatch => {
viewports, viewports,
}; };
const maxActiveIndex = rows * columns - 1;
if (activeViewportIndex > maxActiveIndex) {
dispatch(setViewportActive(0));
}
dispatch(setLayout(layout)); dispatch(setLayout(layout));
}, },
}; };
@@ -43,10 +49,10 @@ const mapDispatchToProps = dispatch => {
const mergeProps = (propsFromState, propsFromDispatch) => { const mergeProps = (propsFromState, propsFromDispatch) => {
const onChangeFromDispatch = propsFromDispatch.onChange; const onChangeFromDispatch = propsFromDispatch.onChange;
const { currentLayout } = propsFromState; const { currentLayout, activeViewportIndex } = propsFromState;
return { return {
onChange: (selectedCell) => onChangeFromDispatch(selectedCell, currentLayout) onChange: selectedCell => onChangeFromDispatch(selectedCell, currentLayout, activeViewportIndex)
}; };
} }
@@ -10,19 +10,9 @@ const mapStateToProps = (state, ownProps) => {
const { viewportIndex } = ownProps; const { viewportIndex } = ownProps;
const toolContextMenuData = state.ui.contextMenu[viewportIndex]; const toolContextMenuData = state.ui.contextMenu[viewportIndex];
let availableTools;
if (
state.extensions &&
state.extensions.cornerstone &&
state.extensions.cornerstone.availableTools
) {
availableTools = state.extensions.cornerstone.availableTools;
}
return { return {
...toolContextMenuData, ...toolContextMenuData,
availableTools,
}; };
}; };
@@ -2,7 +2,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cornerstone from 'cornerstone-core'; import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools'; import cornerstoneTools from 'cornerstone-tools';
import getMeasurementLocationCallback from '../lib/getMeasurementLocationCallback'; // This whole component should live in the Measurements Extension :thinking:
import getMeasurementLocationCallback from '../appExtensions/MeasurementsPanel/getMeasurementLocationCallback';
import './ToolContextMenu.css'; import './ToolContextMenu.css';
@@ -97,12 +98,11 @@ function getNearbyToolData(element, coords, toolTypes) {
return pointNearTool ? nearbyTool : undefined; return pointNearTool ? nearbyTool : undefined;
} }
function getDropdownItems(eventData, isTouchEvent = false, availableTools) { function getDropdownItems(eventData, isTouchEvent = false) {
const nearbyToolData = getNearbyToolData( const nearbyToolData = getNearbyToolData(
eventData.element, eventData.element,
eventData.currentPoints.canvas, eventData.currentPoints.canvas,
toolTypes, toolTypes
availableTools
); );
// Annotate tools for touch events already have a press handle to edit it, has a better UX for deleting it // Annotate tools for touch events already have a press handle to edit it, has a better UX for deleting it
@@ -148,7 +148,6 @@ class ToolContextMenu extends Component {
isTouchEvent: PropTypes.bool.isRequired, isTouchEvent: PropTypes.bool.isRequired,
eventData: PropTypes.object, eventData: PropTypes.object,
onClose: PropTypes.func, onClose: PropTypes.func,
availableTools: PropTypes.array,
visible: PropTypes.bool.isRequired, visible: PropTypes.bool.isRequired,
}; };
@@ -168,12 +167,8 @@ class ToolContextMenu extends Component {
return null; return null;
} }
const { isTouchEvent, eventData, availableTools } = this.props; const { isTouchEvent, eventData } = this.props;
const dropdownItems = getDropdownItems( const dropdownItems = getDropdownItems(eventData, isTouchEvent);
eventData,
isTouchEvent,
availableTools
);
// Skip if there is no dropdown item // Skip if there is no dropdown item
if (!dropdownItems.length) { if (!dropdownItems.length) {
-246
View File
@@ -1,246 +0,0 @@
import OHIF from '@ohif/core';
import updateTableWithNewMeasurementData from './lib/updateTableWithNewMeasurementData';
function getToolLabellingFlowCallback(store) {
const setLabellingFlowDataAction = labellingFlowData => ({
type: 'SET_LABELLING_FLOW_DATA',
labellingFlowData,
});
const setLabellingFlowData = labellingFlowData => {
store.dispatch(setLabellingFlowDataAction(labellingFlowData));
};
return function toolLabellingFlowCallback(
measurementData,
eventData,
doneCallback,
options = {}
) {
const updateLabelling = ({ location, response, description }) => {
// Update the measurement data with the labelling parameters
if (location) {
measurementData.location = location;
}
if (description) {
measurementData.description = description;
}
if (response) {
measurementData.response = response;
}
updateTableWithNewMeasurementData(measurementData);
};
const labellingDoneCallback = () => {
setLabellingFlowData({ visible: false });
};
const labellingFlowData = {
visible: true,
eventData,
measurementData,
skipAddLabelButton: options.skipAddLabelButton,
editLocation: options.editLocation,
editDescription: options.editDescription,
editResponse: options.editResponse,
editDescriptionOnDialog: options.editDescriptionOnDialog,
labellingDoneCallback,
updateLabelling,
};
setLabellingFlowData(labellingFlowData);
};
}
const resetLabellingAndContextMenuAction = state => ({
type: 'RESET_LABELLING_AND_CONTEXT_MENU',
state,
});
const setToolContextMenuDataAction = (viewportIndex, toolContextMenuData) => ({
type: 'SET_TOOL_CONTEXT_MENU_DATA',
viewportIndex,
toolContextMenuData,
});
function getOnRightClickCallback(store) {
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
store.dispatch(resetLabellingAndContextMenuAction());
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
const getOnCloseCallback = viewportIndex => {
return function onClose() {
const toolContextMenuData = {
visible: false,
};
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
};
return function onRightClick(event) {
const eventData = event.detail;
const viewportIndex = parseInt(eventData.element.dataset.viewportIndex, 10);
const toolContextMenuData = {
eventData,
isTouchEvent: false,
onClose: getOnCloseCallback(viewportIndex),
};
setToolContextMenuData(viewportIndex, toolContextMenuData);
};
}
function getOnTouchPressCallback(store) {
const setToolContextMenuData = (viewportIndex, toolContextMenuData) => {
store.dispatch(resetLabellingAndContextMenuAction());
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
const getOnCloseCallback = viewportIndex => {
return function onClose() {
const toolContextMenuData = {
visible: false,
};
store.dispatch(
setToolContextMenuDataAction(viewportIndex, toolContextMenuData)
);
};
};
return function onTouchPress(event) {
const eventData = event.detail;
const viewportIndex = parseInt(eventData.element.dataset.viewportIndex, 10);
const toolContextMenuData = {
eventData,
isTouchEvent: true,
onClose: getOnCloseCallback(viewportIndex),
};
setToolContextMenuData(viewportIndex, toolContextMenuData);
};
}
function getResetLabellingAndContextMenu(store) {
return function resetLabellingAndContextMenu() {
store.dispatch(resetLabellingAndContextMenuAction());
};
}
export default function setupTools(store) {
const toolLabellingFlowCallback = getToolLabellingFlowCallback(store);
const availableTools = [
{ name: 'Pan', mouseButtonMasks: [1, 4] },
{ name: 'Zoom', mouseButtonMasks: [1, 2] },
{ name: 'Wwwc', mouseButtonMasks: [1] },
{ name: 'Magnify' },
{ name: 'WwwcRegion' },
{
name: 'Bidirectional',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{
name: 'Length',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{
name: 'Angle',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{ name: 'StackScroll', mouseButtonMasks: [1] },
{ name: 'Brush', mouseButtonMasks: [1] },
{
name: 'FreehandRoi',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{
name: 'EllipticalRoi',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{
name: 'CircleRoi',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{
name: 'RectangleRoi',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
mouseButtonMasks: [1],
},
{ name: 'DragProbe' },
{ name: 'PanMultiTouch' },
{ name: 'ZoomTouchPinch' },
{ name: 'StackScrollMouseWheel' },
{ name: 'StackScrollMultiTouch' },
{ name: 'Eraser' },
{
name: 'ArrowAnnotate',
props: {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
},
},
];
const onRightClick = getOnRightClickCallback(store);
const onTouchPress = getOnTouchPressCallback(store);
const onNewImage = getResetLabellingAndContextMenu(store);
const onMouseClick = getResetLabellingAndContextMenu(store);
const onTouchStart = getResetLabellingAndContextMenu(store);
const toolAction = OHIF.redux.actions.setExtensionData('cornerstone', {
availableTools,
onNewImage,
onRightClick,
onTouchPress,
onTouchStart,
onMouseClick,
});
store.dispatch(toolAction);
}
+3 -7
View File
@@ -1,4 +1,5 @@
/* Sizes */ /* Sizes */
:root { :root {
--top-bar-height: 40px; --top-bar-height: 40px;
--top-bar-expanded-height: 160px; --top-bar-expanded-height: 160px;
@@ -10,14 +11,8 @@
--study-list-padding-medium-screen: 10px; --study-list-padding-medium-screen: 10px;
} }
/* Fonts */
/* Logo font should be SVG so we don't need to load an entire font */
:root {
--logo-font-family: 'Sanchez';
--logo-font-weight: 300; /* Sanchez, 300 does not exist */
}
/* Transitions */ /* Transitions */
:root { :root {
--transition-duration: 0.3s; --transition-duration: 0.3s;
--transition-effect: ease; --transition-effect: ease;
@@ -25,6 +20,7 @@
} }
/* Thicknesses */ /* Thicknesses */
:root { :root {
--viewport-border-thickness: 1px; --viewport-border-thickness: 1px;
--ui-border-thickness: 1px; --ui-border-thickness: 1px;
+1040 -934
View File
File diff suppressed because it is too large. Load diff