[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:
James PettsandDanny Brown authored and GitHub committed 2020-07-22 19:40:40 +02:00
1 parent 4985fbf5a6
commit a4f286feee
26 files changed
+438 -196

No files matched your search

+1 -1
View File
@@ -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]
+1 -1
View File
@@ -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",
+58 -27
View File
@@ -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.