Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c5223fcf1 | ||
|
|
8513ad9ef3 | ||
|
|
66d8bc6d6f | ||
|
|
0064a4b1cd | ||
|
|
74ce89b22b | ||
|
|
c92975f555 | ||
|
|
ce6c0533a0 | ||
|
|
4df624b8c4 | ||
|
|
e064fd353e | ||
|
|
458d310c78 | ||
|
|
73bc4d9094 | ||
|
|
7709ebb107 | ||
|
|
559b637290 |
No files matched your search
@@ -3,6 +3,36 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.52.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.1...@ohif/extension-vtk@0.52.2) (2019-10-09)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 🎸 Update vtk viewport for faster image reconstruction ([#1016](https://github.com/OHIF/Viewers/issues/1016)) ([8513ad9](https://github.com/OHIF/Viewers/commit/8513ad9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.52.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.52.0...@ohif/extension-vtk@0.52.1) (2019-10-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.52.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.51.3...@ohif/extension-vtk@0.52.0) (2019-10-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 Synced Window Leveling ([559b637](https://github.com/OHIF/Viewers/commit/559b637)), closes [#558](https://github.com/OHIF/Viewers/issues/558)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.51.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.51.2...@ohif/extension-vtk@0.51.3) (2019-10-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-vtk",
|
||||
"version": "0.51.3",
|
||||
"version": "0.52.2",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -48,11 +48,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"react-vtkjs-viewport": "0.1.2"
|
||||
"react-vtkjs-viewport": "0.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ohif/core": "^1.1.0",
|
||||
"@ohif/ui": "^0.53.0",
|
||||
"@ohif/core": "^1.2.0",
|
||||
"@ohif/ui": "^0.53.1",
|
||||
"cornerstone-tools": "^4.0.9",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.6.1",
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import React, { Component } from "react";
|
||||
import { getImageData, loadImageData } from "react-vtkjs-viewport";
|
||||
import React, { Component } from 'react';
|
||||
import { getImageData, loadImageData } from 'react-vtkjs-viewport';
|
||||
|
||||
import ConnectedVTKViewport from "./ConnectedVTKViewport";
|
||||
import LoadingIndicator from "./LoadingIndicator.js";
|
||||
import OHIF from "@ohif/core";
|
||||
import PropTypes from "prop-types";
|
||||
import cornerstone from "cornerstone-core";
|
||||
import handleSegmentationStorage from "./handleSegmentationStorage.js";
|
||||
import vtkDataArray from "vtk.js/Sources/Common/Core/DataArray";
|
||||
import vtkImageData from "vtk.js/Sources/Common/DataModel/ImageData";
|
||||
import vtkVolume from "vtk.js/Sources/Rendering/Core/Volume";
|
||||
import vtkVolumeMapper from "vtk.js/Sources/Rendering/Core/VolumeMapper";
|
||||
import ConnectedVTKViewport from './ConnectedVTKViewport';
|
||||
import LoadingIndicator from './LoadingIndicator.js';
|
||||
import OHIF from '@ohif/core';
|
||||
import PropTypes from 'prop-types';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import handleSegmentationStorage from './handleSegmentationStorage.js';
|
||||
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
|
||||
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
|
||||
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
|
||||
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
|
||||
import vtkViewportSubscriptionManager from './utils/vtkViewportSubscriptionManager.js';
|
||||
|
||||
const { StackManager } = OHIF.utils;
|
||||
|
||||
@@ -24,7 +25,7 @@ cornerstone.metaData.addProvider(
|
||||
StackManager.setMetadataProvider(metadataProvider);
|
||||
|
||||
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 = {};
|
||||
@@ -42,7 +43,7 @@ const volumeCache = {};
|
||||
*/
|
||||
function createLabelMapImageData(backgroundImageData) {
|
||||
const labelMapData = vtkImageData.newInstance(
|
||||
backgroundImageData.get("spacing", "origin", "direction")
|
||||
backgroundImageData.get('spacing', 'origin', 'direction')
|
||||
);
|
||||
labelMapData.setDimensions(backgroundImageData.getDimensions());
|
||||
labelMapData.computeTransforms();
|
||||
@@ -50,7 +51,7 @@ function createLabelMapImageData(backgroundImageData) {
|
||||
const values = new Uint8Array(backgroundImageData.getNumberOfPoints());
|
||||
const dataArray = vtkDataArray.newInstance({
|
||||
numberOfComponents: 1, // labelmap with single component
|
||||
values
|
||||
values,
|
||||
});
|
||||
labelMapData.getPointData().setScalars(dataArray);
|
||||
|
||||
@@ -61,24 +62,24 @@ class OHIFVTKViewport extends Component {
|
||||
state = {
|
||||
volumes: null,
|
||||
paintFilterLabelMapImageData: null,
|
||||
paintFilterBackgroundImageData: null
|
||||
paintFilterBackgroundImageData: null,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
studies: PropTypes.object,
|
||||
displaySet: PropTypes.object,
|
||||
viewportIndex: PropTypes.number,
|
||||
children: PropTypes.node
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
static id = "OHIFVTKViewport";
|
||||
static id = 'OHIFVTKViewport';
|
||||
|
||||
static init() {
|
||||
console.log("OHIFVTKViewport init()");
|
||||
console.log('OHIFVTKViewport init()');
|
||||
}
|
||||
|
||||
static destroy() {
|
||||
console.log("OHIFVTKViewport destroy()");
|
||||
console.log('OHIFVTKViewport destroy()');
|
||||
StackManager.clearStacks();
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ class OHIFVTKViewport extends Component {
|
||||
} else if (sopInstanceUid) {
|
||||
const index = stack.imageIds.findIndex(imageId => {
|
||||
const sopCommonModule = cornerstone.metaData.get(
|
||||
"sopCommonModule",
|
||||
'sopCommonModule',
|
||||
imageId
|
||||
);
|
||||
if (!sopCommonModule) {
|
||||
@@ -151,7 +152,7 @@ class OHIFVTKViewport extends Component {
|
||||
|
||||
switch (sopClassUid) {
|
||||
case SOP_CLASSES.SEGMENTATION_STORAGE:
|
||||
throw new Error("Not yet implemented");
|
||||
throw new Error('Not yet implemented');
|
||||
|
||||
const data = handleSegmentationStorage(
|
||||
stack.imageIds,
|
||||
@@ -164,7 +165,7 @@ class OHIFVTKViewport extends Component {
|
||||
return loadImageData(imageDataObject).then(() => {
|
||||
return {
|
||||
data: imageDataObject.vtkImageData,
|
||||
labelmap: labelmapDataObject
|
||||
labelmap: labelmapDataObject,
|
||||
};
|
||||
});
|
||||
default:
|
||||
@@ -172,7 +173,7 @@ class OHIFVTKViewport extends Component {
|
||||
|
||||
return loadImageData(imageDataObject).then(() => {
|
||||
return {
|
||||
data: imageDataObject.vtkImageData
|
||||
data: imageDataObject.vtkImageData,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -189,10 +190,16 @@ class OHIFVTKViewport extends Component {
|
||||
volumeActor.setMapper(volumeMapper);
|
||||
volumeMapper.setInputData(data);
|
||||
|
||||
const range = data.getPointData().getScalars().getRange();
|
||||
const range = data
|
||||
.getPointData()
|
||||
.getScalars()
|
||||
.getRange();
|
||||
|
||||
// TODO: For PET we might want to just set this to 0-5 SUV
|
||||
volumeActor.getProperty().getRGBTransferFunction(0).setRange(range[0], range[1]);
|
||||
volumeActor
|
||||
.getProperty()
|
||||
.getRGBTransferFunction(0)
|
||||
.setRange(range[0], range[1]);
|
||||
|
||||
// TODO: Should look into implementing autoAdjustSampleDistance in vtk
|
||||
const sampleDistance =
|
||||
@@ -200,7 +207,7 @@ class OHIFVTKViewport extends Component {
|
||||
Math.sqrt(
|
||||
data
|
||||
.getSpacing()
|
||||
.map((v) => v * v)
|
||||
.map(v => v * v)
|
||||
.reduce((a, b) => a + b, 0)
|
||||
);
|
||||
|
||||
@@ -218,12 +225,12 @@ class OHIFVTKViewport extends Component {
|
||||
displaySetInstanceUid,
|
||||
sopClassUids,
|
||||
sopInstanceUid,
|
||||
frameIndex
|
||||
frameIndex,
|
||||
} = displaySet;
|
||||
|
||||
if (sopClassUids.length > 1) {
|
||||
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.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -249,7 +256,7 @@ class OHIFVTKViewport extends Component {
|
||||
this.setState({
|
||||
volumes: [volumeActor],
|
||||
paintFilterBackgroundImageData: data,
|
||||
paintFilterLabelMapImageData: labelmap
|
||||
paintFilterLabelMapImageData: labelmap,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -257,6 +264,11 @@ class OHIFVTKViewport extends Component {
|
||||
this.setStateFromProps();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.log(this.props.viewportIndex);
|
||||
vtkViewportSubscriptionManager.unsubscribe(this.props.viewportIndex);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { studies, displaySet } = this.props.viewportData;
|
||||
const prevDisplaySet = prevProps.viewportData.displaySet;
|
||||
@@ -279,12 +291,12 @@ class OHIFVTKViewport extends Component {
|
||||
childrenWithProps = this.props.children.map((child, index) => {
|
||||
return React.cloneElement(child, {
|
||||
viewportIndex: this.props.viewportIndex,
|
||||
key: index
|
||||
key: index,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const style = { width: "100%", height: "100%", position: "relative" };
|
||||
const style = { width: '100%', height: '100%', position: 'relative' };
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
|
||||
import setMPRLayout from './utils/setMPRLayout.js';
|
||||
import setViewportToVTK from './utils/setViewportToVTK.js';
|
||||
import vtkViewportSubscriptionManager from './utils/vtkViewportSubscriptionManager.js';
|
||||
import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
|
||||
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
|
||||
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
|
||||
@@ -263,16 +264,19 @@ const actions = {
|
||||
|
||||
apis = apiByViewport;
|
||||
|
||||
/*const rgbTransferFunction = apiByViewport[0].volumes[0]
|
||||
const rgbTransferFunction = apiByViewport[0].volumes[0]
|
||||
.getProperty()
|
||||
.getRGBTransferFunction(0);
|
||||
rgbTransferFunction.onModified(() => {
|
||||
|
||||
const onModifiedSubscription = rgbTransferFunction.onModified(() => {
|
||||
apiByViewport.forEach(a => {
|
||||
const renderWindow = a.genericRenderWindow.getRenderWindow();
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
});*/
|
||||
});
|
||||
|
||||
vtkViewportSubscriptionManager.pushSubscription(0, onModifiedSubscription);
|
||||
|
||||
apiByViewport.forEach((api, index) => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
const subscriptions = [];
|
||||
|
||||
// This is pretty hacky right now, but it makes sure we don't keep adding subscriptions.
|
||||
// TODO -> Nuke this and move it up a layer once we have more vigorous layout support.
|
||||
|
||||
const vtkViewportSubscriptionManager = {
|
||||
subscriptions,
|
||||
pushSubscription(viewportIndex, subscription) {
|
||||
if (!Array.isArray(subscriptions[viewportIndex])) {
|
||||
subscriptions[viewportIndex] = [];
|
||||
}
|
||||
|
||||
subscriptions[viewportIndex].push(subscription);
|
||||
},
|
||||
unsubscribe(viewportIndex) {
|
||||
if (!subscriptions[viewportIndex]) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (subscriptions[viewportIndex].length) {
|
||||
subscriptions[viewportIndex].pop().unsubscribe();
|
||||
}
|
||||
|
||||
subscriptions[viewportIndex] = null;
|
||||
},
|
||||
};
|
||||
|
||||
export default vtkViewportSubscriptionManager;
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.2.0](https://github.com/OHIF/Viewers/compare/@ohif/core@1.1.0...@ohif/core@1.2.0) (2019-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* OHIF-1002 Study lazy load should be true by default ([#1004](https://github.com/OHIF/Viewers/issues/1004)) ([66d8bc6](https://github.com/OHIF/Viewers/commit/66d8bc6))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Allow a server requestOptions.auth to be a function that returns the Authorization header. ([#928](https://github.com/OHIF/Viewers/issues/928)) ([0064a4b](https://github.com/OHIF/Viewers/commit/0064a4b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.1.0](https://github.com/OHIF/Viewers/compare/@ohif/core@1.0.2...@ohif/core@1.1.0) (2019-10-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/core",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"description": "Generic business logic for web-based medical imaging applications",
|
||||
"author": "OHIF Core Team",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -9,7 +9,7 @@ import user from '../user';
|
||||
* @export
|
||||
* @param {Object} [server={}]
|
||||
* @param {Object} [server.requestOptions]
|
||||
* @param {string} [server.requestOptions.auth]
|
||||
* @param {string|function} [server.requestOptions.auth]
|
||||
* @returns {Object} { Authorization }
|
||||
*/
|
||||
export default function getAuthorizationHeader({ requestOptions } = {}) {
|
||||
@@ -19,8 +19,13 @@ export default function getAuthorizationHeader({ requestOptions } = {}) {
|
||||
const accessToken = user && user.getAccessToken && user.getAccessToken();
|
||||
|
||||
if (requestOptions && requestOptions.auth) {
|
||||
// HTTP Basic Auth (user:password)
|
||||
headers.Authorization = `Basic ${btoa(requestOptions.auth)}`;
|
||||
if (typeof requestOptions.auth === 'function') {
|
||||
// Custom Auth Header
|
||||
headers.Authorization = requestOptions.auth(requestOptions);
|
||||
} else {
|
||||
// HTTP Basic Auth (user:password)
|
||||
headers.Authorization = `Basic ${btoa(requestOptions.auth)}`;
|
||||
}
|
||||
} else if (accessToken) {
|
||||
headers.Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ describe('getAuthorizationHeader', () => {
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth', () => {
|
||||
const validServer = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
password: 'dummy_password',
|
||||
},
|
||||
auth: 'dummy_user:dummy_password',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -26,9 +23,7 @@ describe('getAuthorizationHeader', () => {
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth even though there is no password', () => {
|
||||
const validServerWithoutPassword = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
},
|
||||
auth: 'dummy_user',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -43,22 +38,19 @@ describe('getAuthorizationHeader', () => {
|
||||
expect(authentication).toEqual(expectedAuthorizationHeader);
|
||||
});
|
||||
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth even though there is no username', () => {
|
||||
const validServerWithoutPassword = {
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth custom function', () => {
|
||||
const validServerCustomAuth = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
},
|
||||
auth: options => `Basic ${options.token}`,
|
||||
token: 'ZHVtbXlfdXNlcjpkdW1teV9wYXNzd29yZA==',
|
||||
},
|
||||
};
|
||||
|
||||
const expectedAuthorizationHeader = {
|
||||
Authorization: `Basic ${btoa(
|
||||
validServerWithoutPassword.requestOptions.auth
|
||||
)}`,
|
||||
Authorization: `Basic ${validServerCustomAuth.requestOptions.token}`,
|
||||
};
|
||||
|
||||
const authentication = getAuthorizationHeader(validServerWithoutPassword);
|
||||
const authentication = getAuthorizationHeader(validServerCustomAuth);
|
||||
|
||||
expect(authentication).toEqual(expectedAuthorizationHeader);
|
||||
});
|
||||
|
||||
@@ -469,7 +469,7 @@ async function createStudyFromSOPInstanceList(server, sopInstanceList) {
|
||||
* @returns {Object} A study descriptor object
|
||||
*/
|
||||
async function RetrieveMetadata(server, studyInstanceUid) {
|
||||
return (server.enableStudyLazyLoad
|
||||
return (server.enableStudyLazyLoad !== false
|
||||
? lazyLoadStudyMetadata
|
||||
: loadStudyMetadata)(server, studyInstanceUid);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.50.5](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.50.4...@ohif/i18n@0.50.5) (2019-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* CineDialog buttons label ([#998](https://github.com/OHIF/Viewers/issues/998)) ([4df624b](https://github.com/OHIF/Viewers/commit/4df624b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.4](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.50.3...@ohif/i18n@0.50.4) (2019-09-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/i18n",
|
||||
"version": "0.50.4",
|
||||
"version": "0.50.5",
|
||||
"description": "Internationalization library for The OHIF Viewer",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"Next image": "$t(Common:Play) $t(Common:Image)",
|
||||
"Next image": "$t(Common:Next) $t(Common:Image)",
|
||||
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
|
||||
"Previous image": "$t(Common:Previous) $t(Common:Image)",
|
||||
"Skip to first image": "Skip to first $t(Common:Image)",
|
||||
"Skip to last image": "Skip, to last $t(Common:Image)",
|
||||
"Skip to last image": "Skip to last $t(Common:Image)",
|
||||
"fps": "fps"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Next image": " $t(Common:Image) $t(Common:Next)",
|
||||
"Next image": "$t(Common:Image) $t(Common:Next)",
|
||||
"Play / Stop": "$t(Common:Play) / Stop",
|
||||
"Previous image": "$t(Common:Image) $t(Common:Previous)",
|
||||
"Skip to first image": "Ir a la primera $t(Common:Image)",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Next image": "$t(Common:Play) $t(Common:Image)",
|
||||
"Next image": "$t(Common:Next) $t(Common:Image)",
|
||||
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
|
||||
"Previous image": "$t(Common:Previous) $t(Common:Image)",
|
||||
"Skip to first image": "$t(Common:Image)最初にスキップ",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Next image": "$t(Common:Play) $t(Common:Image)",
|
||||
"Next image": "$t(Common:Next) $t(Common:Image)",
|
||||
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
|
||||
"Previous image": "$t(Common:Previous) $t(Common:Image)",
|
||||
"Skip to first image": "Bỏ qua đến đầu $t(Common:Image)",
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.53.1](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.53.0...@ohif/ui@0.53.1) (2019-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Move Series Information to Separate Row ([#990](https://github.com/OHIF/Viewers/issues/990)) ([458d310](https://github.com/OHIF/Viewers/commit/458d310))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.53.0](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.52.0...@ohif/ui@0.53.0) (2019-10-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/ui",
|
||||
"version": "0.53.0",
|
||||
"version": "0.53.1",
|
||||
"description": "A set of React components for Medical Imaging Viewers",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -38,7 +38,6 @@ class ThumbnailEntry extends Component {
|
||||
let className = classnames('ThumbnailEntry noselect', {
|
||||
active: this.props.active,
|
||||
});
|
||||
const infoOnly = false;
|
||||
|
||||
let contents = null;
|
||||
if (this.props.imageSrc || this.props.imageId) {
|
||||
@@ -54,8 +53,10 @@ class ThumbnailEntry extends Component {
|
||||
);
|
||||
} else if (this.props.altImageText) {
|
||||
contents = (
|
||||
<div className={'alt-image-text p-x-1'}>
|
||||
<h1>{this.props.altImageText}</h1>
|
||||
<div className="p-x-1">
|
||||
<div className="alt-image-text">
|
||||
<h1>{this.props.altImageText}</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -69,23 +70,23 @@ class ThumbnailEntry extends Component {
|
||||
>
|
||||
{contents}
|
||||
<div
|
||||
className={infoOnly ? 'series-details info-only' : 'series-details'}
|
||||
className="series-details"
|
||||
>
|
||||
<div className="series-description">
|
||||
{this.props.seriesDescription}
|
||||
</div>
|
||||
<div className="series-information">
|
||||
<div className="item item-series clearfix">
|
||||
<div className="item item-series">
|
||||
<div className="icon">S:</div>
|
||||
<div className="value">{this.props.seriesNumber}</div>
|
||||
</div>
|
||||
{hasInstanceNumber && (
|
||||
<div className="item item-series clearfix">
|
||||
<div className="item item-series">
|
||||
<div className="icon">I:</div>
|
||||
<div className="value">{this.props.instanceNumber}</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="item item-frames clearfix">
|
||||
<div className="item item-frames">
|
||||
<div className="icon">
|
||||
<div />
|
||||
</div>
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
color: var(--text-primary-color);
|
||||
|
||||
.series-details
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: var(--text-primary-color);
|
||||
font-size: 14px
|
||||
line-height: 1.3em
|
||||
@@ -44,9 +42,6 @@
|
||||
position: relative
|
||||
word-wrap: break-word
|
||||
|
||||
.series-description
|
||||
flex-grow: 1
|
||||
|
||||
&.info-only
|
||||
.series-description
|
||||
display: none
|
||||
@@ -67,36 +62,33 @@
|
||||
float: none
|
||||
line-height: 25px
|
||||
|
||||
.value
|
||||
margin-left: 0
|
||||
width: auto
|
||||
|
||||
.series-information
|
||||
padding-right: 4px
|
||||
max-width: 50px
|
||||
display: flex
|
||||
flex-direction: row
|
||||
align-items: center
|
||||
|
||||
.item
|
||||
flex: 1
|
||||
text-align: center
|
||||
|
||||
.item-frames .icon
|
||||
height: 18px
|
||||
|
||||
.value
|
||||
color: var(--text-secondary-color);
|
||||
display: inline-block
|
||||
float: right
|
||||
display: inline
|
||||
font-size: 12px
|
||||
margin-left: 4px
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
width: calc(100% - 15px)
|
||||
|
||||
.icon
|
||||
color: var(--active-color);
|
||||
display: inline-block
|
||||
float: left
|
||||
display: inline
|
||||
font-size: 10px
|
||||
font-weight: 900
|
||||
text-align: right
|
||||
width: 11px
|
||||
|
||||
div
|
||||
background-color: var(--series-count-background-color);
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.4.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.3...@ohif/viewer@1.4.4) (2019-10-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.4.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.2...@ohif/viewer@1.4.3) (2019-10-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.4.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.1...@ohif/viewer@1.4.2) (2019-10-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.4.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.4.0...@ohif/viewer@1.4.1) (2019-10-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.4.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.3.3...@ohif/viewer@1.4.0) (2019-10-03)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
describe('OHIF Cornerstone Toolbar', () => {
|
||||
|
||||
before(() => {
|
||||
cy.openStudy("MISTER^MR");
|
||||
cy.waitDicomImage();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
//Creating aliases for Cornerstone tools buttons
|
||||
cy.get('.toolbar-button:nth-child(2)').as('stackScrollBtn');
|
||||
cy.get('.toolbar-button:nth-child(3)').as('zoomBtn');
|
||||
cy.get('.toolbar-button:nth-child(4)').as('levelsBtn');
|
||||
cy.get('.toolbar-button:nth-child(5)').as('panBtn');
|
||||
cy.get('.toolbar-button:nth-child(6)').as('lengthBtn');
|
||||
cy.get('.toolbar-button:nth-child(7)').as('annotateBtn');
|
||||
cy.get('.toolbar-button:nth-child(8)').as('angleBtn');
|
||||
cy.get('.toolbar-button:nth-child(9)').as('resetBtn');
|
||||
cy.get('.toolbar-button:nth-child(10)').as('cineBtn');
|
||||
cy.get('.expandableToolMenu').as('moreBtn');
|
||||
cy.get('.PluginSwitch > .toolbar-button').as('twodmprBtn');
|
||||
cy.get('.btn-group > .toolbar-button').as('layoutBtn');
|
||||
cy.get('.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton').as('measurementsBtn');
|
||||
cy.get('.viewport-element').as('viewport');
|
||||
cy.get('section.sidepanel.from-right').as('measurementsPanel')
|
||||
//Following best practices, reset should be done before each test
|
||||
cy.resetViewport();
|
||||
})
|
||||
|
||||
|
||||
it('checks if all primary buttons are being displayed', () => {
|
||||
cy.get('@stackScrollBtn').should('be.visible').contains('Stack Scroll');
|
||||
cy.get('@zoomBtn').should('be.visible').contains('Zoom');
|
||||
cy.get('@levelsBtn').should('be.visible').contains('Levels');
|
||||
cy.get('@panBtn').should('be.visible').contains('Pan');
|
||||
cy.get('@lengthBtn').should('be.visible').contains('Length');
|
||||
cy.get('@annotateBtn').should('be.visible').contains('Annotate');
|
||||
cy.get('@angleBtn').should('be.visible').contains('Angle');
|
||||
cy.get('@resetBtn').should('be.visible').contains('Reset');
|
||||
cy.get('@cineBtn').should('be.visible').contains('CINE');
|
||||
cy.get('@moreBtn').should('be.visible').contains('More');
|
||||
cy.get('@twodmprBtn').should('be.visible').contains('2D MPR');
|
||||
cy.get('@layoutBtn').should('be.visible').contains('Layout');
|
||||
});
|
||||
|
||||
|
||||
it('checks if Stack Scroll tool will navigate across all series in the viewport', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@stackScrollBtn')
|
||||
.click()
|
||||
.then(($stackScrollBtn) =>{
|
||||
cy.wrap($stackScrollBtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//drags the mouse inside the viewport to be able to interact with series
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'top', { which: 1 })
|
||||
.trigger('mousemove', 'center', { which: 1 })
|
||||
.trigger('mouseup');
|
||||
|
||||
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-left.overlay-element > div';
|
||||
const expectedText = 'Ser: 1Img: 14 14/26256 x 256Loc: 0.00 mm Thick: 5.00 mm';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('have.text', expectedText);
|
||||
});
|
||||
|
||||
|
||||
it('checks if Zoom tool will zoom in/out an image in the viewport', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@zoomBtn')
|
||||
.click()
|
||||
.then(($zoomBtn) =>{
|
||||
cy.wrap($zoomBtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//drags the mouse inside the viewport to be able to interact with series
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'top', { which: 1 })
|
||||
.trigger('mousemove', 'center', { which: 1 })
|
||||
.trigger('mouseup');
|
||||
|
||||
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div';
|
||||
const expectedText = 'Zoom: 884%W: 820 L: 410Lossless / Uncompressed';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('have.text', expectedText);
|
||||
});
|
||||
|
||||
|
||||
it('checks if Levels tool will change the contrast and brightness of an image in the viewport', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@levelsBtn')
|
||||
.click()
|
||||
.then(($levelsBtn) =>{
|
||||
cy.wrap($levelsBtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//drags the mouse inside the viewport to be able to interact with series
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'top', { which: 1 })
|
||||
.trigger('mousemove', 'center', { which: 1 })
|
||||
.trigger('mouseup')
|
||||
.trigger('mousedown', 'center', { which: 1 })
|
||||
.trigger('mousemove', 'left', { which: 1 })
|
||||
.trigger('mouseup');
|
||||
|
||||
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div';
|
||||
const expectedText = 'Zoom: 211%W: 544 L: 626Lossless / Uncompressed';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('have.text', expectedText);
|
||||
});
|
||||
|
||||
|
||||
it('checks if Pan tool will move the image inside the viewport', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@panBtn')
|
||||
.click()
|
||||
.then(($panBtn) =>{
|
||||
cy.wrap($panBtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//Get image position from cornerstone and check if y axis was modified
|
||||
let cornerstone;
|
||||
let currentPan;
|
||||
|
||||
cy.window()
|
||||
.its('cornerstone')
|
||||
.then((c) => {
|
||||
cornerstone = c;
|
||||
currentPan = () => cornerstone.getEnabledElements()[0].viewport.translation;
|
||||
});
|
||||
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'center', { which: 1 })
|
||||
.trigger('mousemove', 'bottom', { which: 1 })
|
||||
.trigger('mouseup', 'bottom')
|
||||
.then(() => {
|
||||
expect(currentPan().y > 0).to.eq(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('checks if Length annotation can be added on viewport and on measurements panel', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@lengthBtn')
|
||||
.click()
|
||||
.then(($lengthbtn) =>{
|
||||
cy.wrap($lengthbtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//Add annotation on the viewport
|
||||
const firstClick = [150, 100];
|
||||
const secondClick = [130, 170];
|
||||
cy.addLine('.cornerstone-canvas', firstClick, secondClick)
|
||||
|
||||
//Verify if measurement annotation was added into the measurements panel
|
||||
cy.get('@measurementsBtn')
|
||||
.click()
|
||||
.then($measurementsBtn => {
|
||||
cy.get('@measurementsPanel')
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('.measurementItem')
|
||||
.its('length')
|
||||
.should('be.eq', 1);
|
||||
|
||||
cy.wrap($measurementsBtn)
|
||||
.click();
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
it('checks if Angle annotation can be added on viewport and on measurements panel', () => {
|
||||
//Click on button and vefiry if icon is active on toolbar
|
||||
cy.get('@angleBtn')
|
||||
.click()
|
||||
.then(($angleBtn) =>{
|
||||
cy.wrap($angleBtn)
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
//Add annotation on the viewport
|
||||
const initPos = [180, 390];
|
||||
const midPos = [300, 410];
|
||||
const finalPos = [180, 450];
|
||||
cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos);
|
||||
|
||||
//Verify if measurement annotation was added into the measurements panel
|
||||
cy.get('@measurementsBtn')
|
||||
.click()
|
||||
.then($measurementsBtn => {
|
||||
cy.get('@measurementsPanel')
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('.measurementItem')
|
||||
.its('length')
|
||||
.should('be.eq', 2);
|
||||
|
||||
cy.wrap($measurementsBtn)
|
||||
.click();
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
it('checks if Reset tool will reset all changes made on the image', () => {
|
||||
//Make some changes by zooming in and rotating the image
|
||||
cy.imageZoomIn();
|
||||
cy.imageContrast();
|
||||
|
||||
//Click on reset button
|
||||
cy.get('@resetBtn').click()
|
||||
|
||||
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div';
|
||||
const expectedText = 'Zoom: 211%W: 820 L: 410Lossless / Uncompressed';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('have.text', expectedText);
|
||||
});
|
||||
|
||||
|
||||
it('checks if CINE tool will prompt a modal with working controls', () => {
|
||||
//Click on button
|
||||
cy.get('@cineBtn')
|
||||
.click();
|
||||
//Vefiry if cine control overlay is being displayed
|
||||
cy.get('.cine-controls').as('cineControls')
|
||||
.should('be.visible');
|
||||
|
||||
//Test PLAY button
|
||||
cy.get('[title="Play / Stop"]')
|
||||
.click()
|
||||
.wait(100)
|
||||
.click();
|
||||
|
||||
const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-left.overlay-element > div';
|
||||
let expectedText = 'Img: 1 1/26';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('not.have.text', expectedText);
|
||||
|
||||
//Test SKIP TO FIRST IMAGE button
|
||||
cy.get('[title="Skip to first Image"]')
|
||||
.click()
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('contain.text', expectedText);
|
||||
|
||||
//Test NEXT IMAGE button
|
||||
cy.get('[title="Next Image"]') //Title is wrong and was reported on bug #995: https://github.com/OHIF/Viewers/issues/995
|
||||
.click()
|
||||
expectedText = 'Img: 2 2/26';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('contain.text', expectedText);
|
||||
|
||||
//Test SKIP TO LAST IMAGE button
|
||||
cy.get('[title="Skip to last Image"]') //Title is wrong and was reported on bug #995: https://github.com/OHIF/Viewers/issues/995
|
||||
.click()
|
||||
expectedText = 'Img: 27 26/26';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('contain.text', expectedText);
|
||||
|
||||
//Test PREVIOUS IMAGE button
|
||||
cy.get('[title="Previous Image"]')
|
||||
.click()
|
||||
expectedText = 'Img: 26 25/26';
|
||||
cy.get(overlaySeriesInformation)
|
||||
.should('contain.text', expectedText);
|
||||
|
||||
//Click on Cine button
|
||||
cy.get('@cineBtn')
|
||||
.click();
|
||||
//Vefiry if cine control overlay is hidden
|
||||
cy.get('@cineControls')
|
||||
.should('not.be.visible');
|
||||
});
|
||||
|
||||
|
||||
it('checks if More button will prompt a modal with secondary tools', () => {
|
||||
cy.get('@moreBtn')
|
||||
.click();
|
||||
//Verify if overlay is displayed
|
||||
cy.get('.tooltip-toolbar-overlay').as('toolbarOverlay')
|
||||
.should('be.visible');
|
||||
|
||||
let iconName;
|
||||
//Click on one of the secondary tools from the overlay
|
||||
cy.get('.tooltip-inner > :nth-child(1)')
|
||||
.click()
|
||||
.then(($magnifyBtn) =>{
|
||||
cy.wrap($magnifyBtn)
|
||||
.should('have.class', 'active')
|
||||
.find('svg').then(($icon)=>{
|
||||
iconName = $icon.text();
|
||||
})
|
||||
})
|
||||
|
||||
//Check if More button is active and if it has same icon as the secondary tool selected
|
||||
cy.get('@moreBtn')
|
||||
.click()
|
||||
.then(($moreBtn) =>{
|
||||
cy.wrap($moreBtn)
|
||||
.should('have.class', 'active')
|
||||
.contains(iconName);
|
||||
})
|
||||
|
||||
//Verify if overlay is hidden
|
||||
cy.get('@toolbarOverlay')
|
||||
.should('not.be.visible');
|
||||
});
|
||||
|
||||
|
||||
it('checks if Layout tool will multiply the number of viewports displayed', () => {
|
||||
//Click on Layout button and verify if overlay is displayed
|
||||
cy.get('@layoutBtn')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.get('.layoutChooser').as('layoutChooser')
|
||||
.should('be.visible')
|
||||
.find('td')
|
||||
.its('length')
|
||||
.should('be.eq', 9);
|
||||
})
|
||||
|
||||
//verify if layout has changed to 2 viewports
|
||||
cy.get('tbody > :nth-child(1) > :nth-child(2)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 2);
|
||||
})
|
||||
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(2) > :nth-child(1)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 2);
|
||||
})
|
||||
|
||||
//verify if layout has changed to 3 viewports
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(1) > :nth-child(3)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wait(1000);
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 3);
|
||||
})
|
||||
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(3) > :nth-child(1)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 3);
|
||||
})
|
||||
|
||||
//verify if layout has changed to 4 viewports
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(2) > :nth-child(2)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 4);
|
||||
})
|
||||
|
||||
//verify if layout has changed to 6 viewports
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(2) > :nth-child(3)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 6);
|
||||
})
|
||||
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(3) > :nth-child(2)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 6);
|
||||
})
|
||||
|
||||
//verify if layout has changed to 9 viewports
|
||||
cy.get('@layoutBtn').click();
|
||||
cy.get('tbody > :nth-child(3) > :nth-child(3)').click();
|
||||
cy.get('.viewport-container').then(($viewport) =>{
|
||||
cy.wrap($viewport)
|
||||
.its('length')
|
||||
.should('be.eq', 9);
|
||||
})
|
||||
|
||||
//Commented this to avoid throwing an wrong exception at the end of "Layout button" test
|
||||
//this commented section should be uncommented once issue #999 is fixed. (https://github.com/OHIF/Viewers/issues/999)
|
||||
|
||||
//verify if layout has changed to 1 viewport
|
||||
// cy.get('@layoutBtn').click();
|
||||
// cy.get('tbody > :nth-child(1) > :nth-child(1)').click();
|
||||
// cy.get('.viewport-container').then(($viewport) =>{
|
||||
// cy.wrap($viewport)
|
||||
// .its('length')
|
||||
// .should('be.eq', 1);
|
||||
// })
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
TODO: Temporarily commented out because it is failing on CI due to timing issues
|
||||
|
||||
describe('OHIF Study Viewer Page', () => {
|
||||
|
||||
before(() => {
|
||||
@@ -41,10 +40,8 @@ describe('OHIF Study Viewer Page', () => {
|
||||
cy.get(measurementsButton).click();
|
||||
cy.get(rightPanel).should('be.visible');
|
||||
|
||||
|
||||
cy.get(measurementsButton).click();
|
||||
cy.get(rightPanel).should('not.be.enabled');
|
||||
});
|
||||
|
||||
});
|
||||
*/
|
||||
@@ -1,4 +1,6 @@
|
||||
import { DragSimulator } from "../helpers/DragSimulator.js";
|
||||
import { doesNotReject } from "assert";
|
||||
import { disconnect } from "cluster";
|
||||
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
@@ -30,12 +32,114 @@ Cypress.Commands.add('openStudy', (patientName) => {
|
||||
cy.visit('/');
|
||||
cy.get('#patientName')
|
||||
.type(patientName);
|
||||
cy.get('.studylistStudy > .patientName')
|
||||
.contains(patientName)
|
||||
.click();
|
||||
|
||||
cy.get('.studylistStudy > .patientName').as('patientResult')
|
||||
.then({ timeout: 5000 }, ($patientResult) => {
|
||||
cy.contains(patientName)
|
||||
.click();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add('drag', {prevSubject: 'element',},
|
||||
(...args) => DragSimulator.simulate(...args)
|
||||
);
|
||||
|
||||
/**
|
||||
* Command to perform two clicks into two 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).
|
||||
*
|
||||
* @param {*} viewport - Selector for viewport we would like to interact with
|
||||
* @param {number[]} firstClick - Click position [x, y]
|
||||
* @param {number[]} secondClick - Click position [x, y]
|
||||
*/
|
||||
Cypress.Commands.add('addLine', (viewport, firstClick, secondClick) => {
|
||||
|
||||
cy.get(viewport).then(($viewport) => {
|
||||
const [ x1, y1 ] = firstClick;
|
||||
const [ x2, y2 ] = secondClick;
|
||||
|
||||
cy.wrap($viewport)
|
||||
.click(x1, y1, {force: true})
|
||||
.trigger('mousemove', {clientX:x2, clientY:y2})
|
||||
.click(x2, y2, {force: true})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param {*} viewport - Selector for viewport we would like to interact with
|
||||
* @param {number[]} firstClick - Click position [x, y]
|
||||
* @param {number[]} secondClick - Click position [x, y]
|
||||
* @param {number[]} thirdClick - Click position [x, y]
|
||||
*/
|
||||
Cypress.Commands.add('addAngle', (viewport, firstClick, secondClick, thirdClick) => {
|
||||
|
||||
cy.get(viewport).then(($viewport) => {
|
||||
const [ x1, y1 ] = firstClick;
|
||||
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})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//Command to wait DICOM image to load into the viewport
|
||||
Cypress.Commands.add('waitDicomImage', (timeout = 10000) => {
|
||||
cy.window()
|
||||
.its('cornerstone')
|
||||
.then($cornerstone => {
|
||||
return new Cypress.Promise(resolve => {
|
||||
const onEvent = (renderedEvt) => {
|
||||
const element = renderedEvt.detail.element;
|
||||
|
||||
element.removeEventListener('cornerstoneimagerendered', onEvent);
|
||||
$cornerstone.events.removeEventListener('cornerstoneimagerendered', onEvent);
|
||||
resolve();
|
||||
}
|
||||
const onEnabled = (enabledEvt) => {
|
||||
const element = enabledEvt.detail.element;
|
||||
|
||||
element.addEventListener('cornerstoneimagerendered', onEvent);
|
||||
}
|
||||
$cornerstone.events.addEventListener('cornerstoneelementenabled', onEnabled);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
//Command to reset the viewport changes throught the cornerstone method
|
||||
Cypress.Commands.add('resetViewport', () => {
|
||||
cy.get('@resetBtn').click()
|
||||
});
|
||||
|
||||
|
||||
Cypress.Commands.add('imageZoomIn', () => {
|
||||
cy.get('@zoomBtn').click();
|
||||
|
||||
//drags the mouse inside the viewport to be able to interact with series
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'top', { which: 1 })
|
||||
.trigger('mousemove', 'center', { which: 1 })
|
||||
.trigger('mouseup');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('imageContrast', () => {
|
||||
cy.get('@levelsBtn').click();
|
||||
|
||||
//drags the mouse inside the viewport to be able to interact with series
|
||||
cy.get('@viewport')
|
||||
.trigger('mousedown', 'center', { which: 1 })
|
||||
.trigger('mousemove', 'top', { which: 1 })
|
||||
.trigger('mouseup');
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/viewer",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.5",
|
||||
"description": "OHIF Viewer",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
@@ -46,14 +46,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@ohif/core": "^1.1.0",
|
||||
"@ohif/core": "^1.2.0",
|
||||
"@ohif/extension-cornerstone": "^2.0.0",
|
||||
"@ohif/extension-dicom-html": "^1.0.0",
|
||||
"@ohif/extension-dicom-microscopy": "^0.50.6",
|
||||
"@ohif/extension-dicom-pdf": "^1.0.0",
|
||||
"@ohif/extension-vtk": "^0.51.3",
|
||||
"@ohif/i18n": "^0.50.4",
|
||||
"@ohif/ui": "^0.53.0",
|
||||
"@ohif/extension-vtk": "^0.52.2",
|
||||
"@ohif/i18n": "^0.50.5",
|
||||
"@ohif/ui": "^0.53.1",
|
||||
"@tanem/react-nprogress": "^1.1.25",
|
||||
"classnames": "^2.2.6",
|
||||
"core-js": "^3.2.1",
|
||||
|
||||
@@ -2272,6 +2272,16 @@
|
||||
once "^1.4.0"
|
||||
universal-user-agent "^4.0.0"
|
||||
|
||||
"@ohif/extension-cornerstone@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ohif/extension-cornerstone/-/extension-cornerstone-2.0.0.tgz#b4ee3b594212502192cdd311a100354857280548"
|
||||
integrity sha512-hvJ3t2GRcu906NiYpUWaJIB9ja/M/MKEYLy19t4XBFpqf4VqoezR2KJpZelmZjQscXGaDQeZgvr3DJO5Nva8Uw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
classnames "^2.2.6"
|
||||
lodash.throttle "^4.1.1"
|
||||
react-cornerstone-viewport "0.1.30"
|
||||
|
||||
"@ohif/i18n@^0.2.3":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@ohif/i18n/-/i18n-0.2.5.tgz#2b92a78109823ce0f50dd590201d980a5fd64974"
|
||||
@@ -14959,10 +14969,10 @@ react-transition-group@^4.1.1:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-vtkjs-viewport@0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.1.2.tgz#087af73b1c46627c5079d25ab1b0d3866cb7b06b"
|
||||
integrity sha512-1UejtY8i6LhK2FXouD7so2VRYbdjo7w80VUQ6EesyurBAZYAYW3ppvAlBjtvMlJhYZn13wwE3gTFAbrHPVPjDw==
|
||||
react-vtkjs-viewport@0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.1.4.tgz#f5ecc7dd52ab065d54656f36851f49b058ba683f"
|
||||
integrity sha512-07hVFJJ9LTy+Z9dgdPiPkaohVb013bgjNgH29MVafnjwH92YOXJzfFbf8/yzzVIZsYCETFf7rVw+oMGQJs5TAA==
|
||||
dependencies:
|
||||
date-fns "^2.2.1"
|
||||
gl-matrix "^3.1.0"
|
||||
|
||||
Reference in new issue
Block a user