fix(layouts): and fix thumbnail in touch and update migration guide for 3.8 release (#4052)
This commit is contained in:
1 parent
28bc8914a8
commit
d250d04580
30 files changed
+209
-158
No files matched your search
@@ -47,6 +47,8 @@ describe('OHIF Study List', function () {
|
||||
'[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]'
|
||||
).click();
|
||||
cy.get('[data-cy="return-to-work-list"]').click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('Juno');
|
||||
@@ -72,6 +74,8 @@ describe('OHIF Study List', function () {
|
||||
'[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]'
|
||||
).click();
|
||||
cy.get('[data-cy="return-to-work-list"]').click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('0000003');
|
||||
@@ -82,6 +86,7 @@ describe('OHIF Study List', function () {
|
||||
cy.get('@AccessionNumber').type('321');
|
||||
//Wait result list to be displayed
|
||||
cy.waitStudyList();
|
||||
cy.wait(2000);
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('321');
|
||||
@@ -92,11 +97,15 @@ describe('OHIF Study List', function () {
|
||||
cy.get('@AccessionNumber').type('0000155811');
|
||||
//Wait result list to be displayed
|
||||
cy.waitStudyList();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('[data-cy="studyRow-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]').click();
|
||||
cy.get(
|
||||
'[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]'
|
||||
).click();
|
||||
cy.get('[data-cy="return-to-work-list"]').click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('0000155811');
|
||||
@@ -107,6 +116,8 @@ describe('OHIF Study List', function () {
|
||||
cy.get('@StudyDescription').type('PETCT');
|
||||
//Wait result list to be displayed
|
||||
cy.waitStudyList();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('PETCT');
|
||||
@@ -117,13 +128,15 @@ describe('OHIF Study List', function () {
|
||||
cy.get('@StudyDescription').type('PETCT');
|
||||
//Wait result list to be displayed
|
||||
cy.waitStudyList();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get('[data-cy="studyRow-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]').click();
|
||||
cy.get(
|
||||
'[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]'
|
||||
).click();
|
||||
cy.get('[data-cy="return-to-work-list"]').click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get('@searchResult2').should($list => {
|
||||
expect($list.length).to.be.eq(1);
|
||||
expect($list).to.contain('PETCT');
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.70.8",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.70.9",
|
||||
"@emotion/serialize": "^1.1.3",
|
||||
"@ohif/core": "3.8.0-beta.85",
|
||||
"@ohif/extension-cornerstone": "3.8.0-beta.85",
|
||||
|
||||
@@ -62,6 +62,13 @@ function App({ config, defaultExtensions, defaultModes }) {
|
||||
const appConfigState = init.appConfig;
|
||||
const { routerBasename, modes, dataSources, oidc, showStudyList } = appConfigState;
|
||||
|
||||
// get the maximum 3D texture size
|
||||
const canvas = document.createElement('canvas');
|
||||
const gl = canvas.getContext('webgl2');
|
||||
|
||||
const max3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE);
|
||||
appConfigState.max3DTextureSize = max3DTextureSize;
|
||||
|
||||
const {
|
||||
uiDialogService,
|
||||
uiModalService,
|
||||
|
||||
@@ -103,20 +103,12 @@ function ViewerViewportGrid(props) {
|
||||
|
||||
const _getUpdatedViewports = useCallback(
|
||||
(viewportId, displaySetInstanceUID) => {
|
||||
if (!isHangingProtocolLayout) {
|
||||
return [
|
||||
{
|
||||
viewportId,
|
||||
displaySetInstanceUIDs: [displaySetInstanceUID],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
let updatedViewports = [];
|
||||
try {
|
||||
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
||||
viewportId,
|
||||
displaySetInstanceUID
|
||||
displaySetInstanceUID,
|
||||
isHangingProtocolLayout
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.70.8",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.70.9",
|
||||
"@ohif/ui": "3.8.0-beta.85",
|
||||
"cornerstone-math": "0.1.9",
|
||||
"dicom-parser": "^1.8.21"
|
||||
|
||||
@@ -601,17 +601,25 @@ export default class HangingProtocolService extends PubSubService {
|
||||
};
|
||||
}
|
||||
|
||||
getViewportsRequireUpdate(viewportId, displaySetInstanceUID) {
|
||||
const { displaySetService } = this._servicesManager.services;
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
if (displaySet?.unsupported) {
|
||||
throw new Error('Unsupported displaySet');
|
||||
}
|
||||
/**
|
||||
* This will return the viewports that need to be updated based on the
|
||||
* hanging protocol layout and the displaySetInstanceUID that needs to be updated.
|
||||
*
|
||||
* This is useful, when for instance we drag and drop a displaySet into a viewport
|
||||
* which is in MPR, and we need to update the other viewports that are showing the same
|
||||
* layout.
|
||||
*
|
||||
* However, sometimes since we get out of sync with the hanging protocol layout, when
|
||||
* the user use the custom grid layout, we should not update the other viewports, and that is
|
||||
* when the isHangingProtocolLayout is set to false.
|
||||
*
|
||||
* @param viewportId - the id of the viewport that needs to be updated
|
||||
* @param displaySetInstanceUID - the displaySetInstanceUID that needs to be updated
|
||||
* @param isHangingProtocolLayout - whether the layout is a hanging protocol layout
|
||||
* @returns
|
||||
*/
|
||||
getViewportsRequireUpdate(viewportId, displaySetInstanceUID, isHangingProtocolLayout = true) {
|
||||
const newDisplaySetInstanceUID = displaySetInstanceUID;
|
||||
const protocol = this.protocol;
|
||||
const protocolStage = protocol.stages[this.stageIndex];
|
||||
const protocolViewports = protocolStage.viewports;
|
||||
|
||||
const defaultReturn = [
|
||||
{
|
||||
viewportId,
|
||||
@@ -619,6 +627,19 @@ export default class HangingProtocolService extends PubSubService {
|
||||
},
|
||||
];
|
||||
|
||||
if (!isHangingProtocolLayout) {
|
||||
return defaultReturn;
|
||||
}
|
||||
|
||||
const { displaySetService } = this._servicesManager.services;
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
if (displaySet?.unsupported) {
|
||||
throw new Error('Unsupported displaySet');
|
||||
}
|
||||
const protocol = this.protocol;
|
||||
const protocolStage = protocol.stages[this.stageIndex];
|
||||
const protocolViewports = protocolStage.viewports;
|
||||
|
||||
if (!protocolViewports) {
|
||||
return defaultReturn;
|
||||
}
|
||||
@@ -1084,9 +1105,8 @@ export default class HangingProtocolService extends PubSubService {
|
||||
options
|
||||
): HangingProtocol.ViewportMatchDetails {
|
||||
if (this.protocol.id !== protocolId) {
|
||||
throw new Error(
|
||||
`Currently applied protocol ${this.protocol.id} is different from ${protocolId}`
|
||||
);
|
||||
console.warn('setting protocol');
|
||||
this.protocol = this.getProtocolById(protocolId);
|
||||
}
|
||||
const protocol = this.protocol;
|
||||
const stage = protocol.stages[stageIdx];
|
||||
|
||||
@@ -10,7 +10,7 @@ const iopTolerance = 0.01;
|
||||
*
|
||||
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
|
||||
*/
|
||||
export default function isDisplaySetReconstructable(instances) {
|
||||
export default function isDisplaySetReconstructable(instances, appConfig) {
|
||||
if (!instances.length) {
|
||||
return { value: false };
|
||||
}
|
||||
@@ -18,6 +18,14 @@ export default function isDisplaySetReconstructable(instances) {
|
||||
|
||||
const isMultiframe = firstInstance.NumberOfFrames > 1;
|
||||
|
||||
if (appConfig) {
|
||||
const rows = toNumber(firstInstance.Rows);
|
||||
const columns = toNumber(firstInstance.Columns);
|
||||
|
||||
if (rows > appConfig.max3DTextureSize || columns > appConfig.max3DTextureSize) {
|
||||
return { value: false };
|
||||
}
|
||||
}
|
||||
// We used to check is reconstructable modalities here, but the logic is removed
|
||||
// in favor of the calculation by metadata (orientation and positions)
|
||||
|
||||
|
||||
@@ -135,3 +135,8 @@ Additional Resources
|
||||
## leftPanelDefaultClosed and rightPanelDefaultClosed
|
||||
|
||||
Now they are renamed to `leftPanelClosed` and `rightPanelClosed` respectively.
|
||||
|
||||
|
||||
## StudyInstanceUID in the URL param
|
||||
|
||||
Previously there were two params that you could choose: seriesInstanceUID and seriesInstanceUIDs, they have been replaced with seriesInstanceUIDs so even if you would like to filter one series use ``seriesInstanceUIDs`
|
||||
@@ -69,7 +69,6 @@ list as state stores are added:
|
||||
* `viewportGridStore` has viewport grid restore information for returning to an earlier grid layout.
|
||||
* `reuseIdMap` has a map of names to display sets for preserving user changes to hp display set selections.
|
||||
* `hanging` has a map of the hanging protocol stage information applied (HPInfo)
|
||||
* `toggleHangingProtocol` has the previously applied hanging protocol, to toggle an HP off.
|
||||
|
||||
### Cornerstone Extension Stores
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { useDrag } from 'react-dnd';
|
||||
@@ -35,6 +35,19 @@ const Thumbnail = ({
|
||||
},
|
||||
});
|
||||
|
||||
const [lastTap, setLastTap] = useState(0);
|
||||
|
||||
const handleTouchEnd = e => {
|
||||
const currentTime = new Date().getTime();
|
||||
const tapLength = currentTime - lastTap;
|
||||
if (tapLength < 300 && tapLength > 0) {
|
||||
onDoubleClick(e);
|
||||
} else {
|
||||
onClick(e);
|
||||
}
|
||||
setLastTap(currentTime);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
@@ -45,6 +58,7 @@ const Thumbnail = ({
|
||||
data-cy={`study-browser-thumbnail`}
|
||||
onClick={onClick}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
@@ -56,9 +70,6 @@ const Thumbnail = ({
|
||||
? 'border-primary-light border-2'
|
||||
: 'border-secondary-light border hover:border-blue-300'
|
||||
)}
|
||||
style={{
|
||||
margin: isActive ? '0' : '1px',
|
||||
}}
|
||||
>
|
||||
{imageSrc ? (
|
||||
<img
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDrag } from 'react-dnd';
|
||||
@@ -30,6 +30,19 @@ const ThumbnailNoImage = ({
|
||||
},
|
||||
});
|
||||
|
||||
const [lastTap, setLastTap] = useState(0);
|
||||
|
||||
const handleTouchEnd = e => {
|
||||
const currentTime = new Date().getTime();
|
||||
const tapLength = currentTime - lastTap;
|
||||
if (tapLength < 300 && tapLength > 0) {
|
||||
onDoubleClick(e);
|
||||
} else {
|
||||
onClick(e);
|
||||
}
|
||||
setLastTap(currentTime);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
@@ -42,6 +55,7 @@ const ThumbnailNoImage = ({
|
||||
id={`thumbnail-${displaySetInstanceUID}`}
|
||||
onClick={onClick}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
data-cy={`study-browser-thumbnail-no-image`}
|
||||
|
||||
@@ -224,7 +224,6 @@ export function ViewportGridProvider({ children, service }) {
|
||||
// If empty viewportOptions, we use numRow and numCols to calculate number of viewports
|
||||
const hasOptions = layoutOptions?.length;
|
||||
const viewports = new Map<string, Viewport>();
|
||||
|
||||
// Options is a temporary state store which can be used by the
|
||||
// findOrCreate to store state about already found viewports. Typically,
|
||||
// it will be used to store the display set UID's which are already
|
||||
@@ -237,7 +236,21 @@ export function ViewportGridProvider({ children, service }) {
|
||||
for (let col = 0; col < numCols; col++) {
|
||||
const position = col + row * numCols;
|
||||
const layoutOption = layoutOptions[position];
|
||||
const positionId = layoutOption?.positionId || `${col}-${row}`;
|
||||
|
||||
let xPos, yPos, w, h;
|
||||
if (layoutOptions && layoutOptions[position]) {
|
||||
({ x: xPos, y: yPos, width: w, height: h } = layoutOptions[position]);
|
||||
} else {
|
||||
w = 1 / numCols;
|
||||
h = 1 / numRows;
|
||||
xPos = col * w;
|
||||
yPos = row * h;
|
||||
}
|
||||
|
||||
const colIndex = Math.round(xPos * numCols);
|
||||
const rowIndex = Math.round(yPos * numRows);
|
||||
|
||||
const positionId = layoutOption?.positionId || `${colIndex}-${rowIndex}`;
|
||||
|
||||
if (hasOptions && position >= layoutOptions.length) {
|
||||
continue;
|
||||
@@ -264,16 +277,6 @@ export function ViewportGridProvider({ children, service }) {
|
||||
// and it is part of the read only state
|
||||
viewports.set(viewport.viewportId, viewport);
|
||||
|
||||
let xPos, yPos, w, h;
|
||||
if (layoutOptions && layoutOptions[position]) {
|
||||
({ x: xPos, y: yPos, width: w, height: h } = layoutOptions[position]);
|
||||
} else {
|
||||
w = 1 / numCols;
|
||||
h = 1 / numRows;
|
||||
xPos = col * w;
|
||||
yPos = row * h;
|
||||
}
|
||||
|
||||
Object.assign(viewport, {
|
||||
width: w,
|
||||
height: h,
|
||||
|
||||
Reference in new issue
Block a user