[OHIF 284] - JumpToMeasurement + prevent layout change on scroll Prevent layout change on scroll (#1889)
* No more setting on debounce, jumpToMeasurement service set up. * Fix bug causing a race condition sometimes if you click super fast. * Optimise rendering of Tracking viewport slightly. * element => targetElement * Remove complete TODO * Respond to reviewer comments. * Fix e2e workflow. * Fix regression that removed highlighting on jump to. * Make sure jump to works from panel as well as viewport. * Fix typo and remove debugger. Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
1 parent
4985fbf5a6
commit
a4f286feee
26 files changed
+438
-196
No files matched your search
@@ -38,7 +38,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"ajv": "^6.10.0",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicomweb-client": "^0.6.0",
|
||||
"immer": "6.0.2",
|
||||
"isomorphic-base64": "^1.0.2",
|
||||
|
||||
@@ -46,6 +46,20 @@ export default class DisplaySetService {
|
||||
);
|
||||
};
|
||||
|
||||
getDisplaySetForSOPInstanceUID(SOPInstanceUID, SeriesInstanceUID) {
|
||||
const displaySets = SeriesInstanceUID
|
||||
? this.getDisplaySetsForSeries(SeriesInstanceUID)
|
||||
: this.getDisplaySetCache();
|
||||
|
||||
const displaySet = displaySets.find(ds => {
|
||||
return (
|
||||
ds.images && ds.images.some(i => i.SOPInstanceUID === SOPInstanceUID)
|
||||
);
|
||||
});
|
||||
|
||||
return displaySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} displaySetInstanceUID
|
||||
* @returns {object} displaySet
|
||||
|
||||
@@ -53,6 +53,7 @@ const EVENTS = {
|
||||
MEASUREMENT_ADDED: 'event::measurement_added',
|
||||
MEASUREMENT_REMOVED: 'event::measurement_removed',
|
||||
MEASUREMENTS_CLEARED: 'event::measurements_cleared',
|
||||
JUMP_TO_MEASUREMENT: 'event:jump_to_measurement',
|
||||
};
|
||||
|
||||
const VALUE_TYPES = {
|
||||
@@ -70,6 +71,7 @@ class MeasurementService {
|
||||
this.mappings = {};
|
||||
this.measurements = {};
|
||||
this.listeners = {};
|
||||
this._jumpToMeasurementCache = {};
|
||||
Object.defineProperty(this, 'EVENTS', {
|
||||
value: EVENTS,
|
||||
writable: false,
|
||||
@@ -498,6 +500,40 @@ class MeasurementService {
|
||||
this._broadcastChange(this.EVENTS.MEASUREMENTS_CLEARED);
|
||||
}
|
||||
|
||||
jumpToMeasurement(viewportIndex, id) {
|
||||
const measurement = this.measurements[id];
|
||||
|
||||
if (!measurement) {
|
||||
log.warn(`No id provided, or unable to find measurement by id.`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._addJumpToMeasurement(viewportIndex, id);
|
||||
|
||||
const eventName = this.EVENTS.JUMP_TO_MEASUREMENT;
|
||||
|
||||
const hasListeners = Object.keys(this.listeners).length > 0;
|
||||
const hasCallbacks = Array.isArray(this.listeners[eventName]);
|
||||
|
||||
if (hasListeners && hasCallbacks) {
|
||||
this.listeners[eventName].forEach(listener => {
|
||||
listener.callback({ viewportIndex, measurement });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_addJumpToMeasurement(viewportIndex, id) {
|
||||
this._jumpToMeasurementCache[viewportIndex] = id;
|
||||
}
|
||||
|
||||
getJumpToMeasurement(viewportIndex) {
|
||||
return this._jumpToMeasurementCache[viewportIndex];
|
||||
}
|
||||
|
||||
removeJumpToMeasurement(viewportIndex) {
|
||||
delete this._jumpToMeasurementCache[viewportIndex];
|
||||
}
|
||||
|
||||
_getMappingByMeasurementSource(measurementId, definition) {
|
||||
const measurement = this.getMeasurement(measurementId);
|
||||
if (this._isValidSource(measurement.source)) {
|
||||
|
||||
@@ -27,14 +27,10 @@ export function ViewportGridProvider({ children, service }) {
|
||||
return { ...state, ...{ activeViewportIndex: action.payload } };
|
||||
}
|
||||
case 'SET_DISPLAYSET_FOR_VIEWPORT': {
|
||||
const {
|
||||
viewportIndex,
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
} = action.payload;
|
||||
const { viewportIndex, displaySetInstanceUID } = action.payload;
|
||||
const viewports = state.viewports.slice();
|
||||
|
||||
viewports[viewportIndex] = { displaySetInstanceUID, imageIndex };
|
||||
viewports[viewportIndex] = { displaySetInstanceUID };
|
||||
|
||||
return { ...state, ...{ viewports }, cachedLayout: null };
|
||||
}
|
||||
@@ -63,7 +59,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
numCols: 1,
|
||||
numRows: 1,
|
||||
activeViewportIndex: 0,
|
||||
viewports: [{ displaySetInstanceUID: null, imageIndex: null }],
|
||||
viewports: [{ displaySetInstanceUID: null }],
|
||||
cachedLayout: null,
|
||||
};
|
||||
}
|
||||
@@ -96,13 +92,12 @@ export function ViewportGridProvider({ children, service }) {
|
||||
[dispatch]
|
||||
);
|
||||
const setDisplaysetForViewport = useCallback(
|
||||
({ viewportIndex, displaySetInstanceUID, imageIndex }) =>
|
||||
({ viewportIndex, displaySetInstanceUID }) =>
|
||||
dispatch({
|
||||
type: 'SET_DISPLAYSET_FOR_VIEWPORT',
|
||||
payload: {
|
||||
viewportIndex,
|
||||
displaySetInstanceUID,
|
||||
imageIndex,
|
||||
},
|
||||
}),
|
||||
[dispatch]
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.18.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.16.0",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"dicomweb-client": "^0.4.4",
|
||||
"dotenv-webpack": "^1.7.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* CSS Grid Reference: http://grid.malven.co/
|
||||
*/
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
|
||||
import EmptyViewport from './EmptyViewport';
|
||||
@@ -11,13 +11,18 @@ import classNames from 'classnames';
|
||||
|
||||
function ViewerViewportGrid(props) {
|
||||
const { servicesManager, viewportComponents, dataSource } = props;
|
||||
const [
|
||||
{ numCols, numRows, activeViewportIndex, viewports, cachedLayout },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
|
||||
const {
|
||||
numCols,
|
||||
numRows,
|
||||
activeViewportIndex,
|
||||
viewports,
|
||||
cachedLayout,
|
||||
} = viewportGrid;
|
||||
|
||||
// TODO -> Need some way of selecting which displaySets hit the viewports.
|
||||
const { DisplaySetService } = servicesManager.services;
|
||||
const { DisplaySetService, MeasurementService } = servicesManager.services;
|
||||
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = DisplaySetService.subscribe(
|
||||
@@ -40,30 +45,56 @@ function ViewerViewportGrid(props) {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// TODO -> Make a HangingProtocolService
|
||||
const HangingProtocolService = displaySets => {
|
||||
let displaySetInstanceUID;
|
||||
useEffect(() => {
|
||||
const { unsubscribe } = MeasurementService.subscribe(
|
||||
MeasurementService.EVENTS.JUMP_TO_MEASUREMENT,
|
||||
({ viewportIndex, measurement }) => {
|
||||
const referencedDisplaySetInstanceUID =
|
||||
measurement.displaySetInstanceUID;
|
||||
|
||||
// Fallback
|
||||
if (!displaySets || !displaySets.length) {
|
||||
const displaySet = DisplaySetService.activeDisplaySets[0];
|
||||
displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
} else {
|
||||
const displaySet = displaySets[0];
|
||||
displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
}
|
||||
// If the viewport does not contain the displaySet, then hang that displaySet.
|
||||
if (
|
||||
viewports[viewportIndex].displaySetInstanceUID !==
|
||||
referencedDisplaySetInstanceUID
|
||||
) {
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex,
|
||||
displaySetInstanceUID: referencedDisplaySetInstanceUID,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
numRows: 1,
|
||||
numCols: 1,
|
||||
activeViewportIndex: 0,
|
||||
viewports: [
|
||||
{
|
||||
displaySetInstanceUID,
|
||||
},
|
||||
],
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
};
|
||||
}, [viewports]);
|
||||
|
||||
// TODO -> Make a HangingProtocolService
|
||||
// Commented out whilst not in use to avoid pointlessly regenerating this function.
|
||||
// const HangingProtocolService = displaySets => {
|
||||
// let displaySetInstanceUID;
|
||||
|
||||
// // Fallback
|
||||
// if (!displaySets || !displaySets.length) {
|
||||
// const displaySet = DisplaySetService.activeDisplaySets[0];
|
||||
// displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
// } else {
|
||||
// const displaySet = displaySets[0];
|
||||
// displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
||||
// }
|
||||
|
||||
// return {
|
||||
// numRows: 1,
|
||||
// numCols: 1,
|
||||
// activeViewportIndex: 0,
|
||||
// viewports: [
|
||||
// {
|
||||
// displaySetInstanceUID,
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
// };
|
||||
|
||||
const onDoubleClick = viewportIndex => {
|
||||
// TODO -> Disabled for now.
|
||||
|
||||
Reference in new issue
Block a user