OHIF-223: Add "Clear" all measurements to annotation toolbar (#1861)

* Add clear button

* Use james event

* Create new commands module to default
This commit is contained in:
Igor Octaviano 2020-07-03 13:39:41 -03:00 committed by GitHub
parent 61fc093fc5
commit 11fbe4cf01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 112 additions and 7 deletions

View File

@ -121,6 +121,7 @@ const commandsModule = ({ servicesManager }) => {
lesionNamingNumber,
measurementNumber,
} = measurementData;
if (!_id) {
return;
}

View File

@ -271,6 +271,7 @@ const _connectToolsToMeasurementService = measurementService => {
const csToolsVer4MeasurementSource = _initMeasurementService(
measurementService
);
_connectMeasurementServiceToTools(measurementService, csToolsVer4MeasurementSource);
const { addOrUpdate, remove } = csToolsVer4MeasurementSource;
const elementEnabledEvt = cornerstone.EVENTS.ELEMENT_ENABLED;
@ -335,6 +336,30 @@ const _connectToolsToMeasurementService = measurementService => {
});
};
const _connectMeasurementServiceToTools = (measurementService, measurementSource) => {
const { MEASUREMENTS_CLEARED, MEASUREMENT_REMOVED } = measurementService.EVENTS;
const sourceId = measurementSource.id;
measurementService.subscribe(MEASUREMENTS_CLEARED, () => {
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
{}
);
cornerstone.getEnabledElements().forEach(enabledElement => {
cornerstone.updateImage(enabledElement.element);
});
});
/* TODO: Remove per measurement
measurementService.subscribe(MEASUREMENT_REMOVED,
({ source, measurement }) => {
if ([sourceId].includes(source.id)) {
// const annotation = getAnnotation('Length', measurement.id);
// iterate tool state
}
}
); */
};
// const {
// MEASUREMENT_ADDED,
// MEASUREMENT_UPDATED,

View File

@ -23,9 +23,10 @@ export default function PanelMeasurementTable({
const added = MeasurementService.EVENTS.MEASUREMENT_ADDED;
const updated = MeasurementService.EVENTS.MEASUREMENT_UPDATED;
const removed = MeasurementService.EVENTS.MEASUREMENT_REMOVED;
const cleared = MeasurementService.EVENTS.MEASUREMENTS_CLEARED;
const subscriptions = [];
[added, updated, removed].forEach(evt => {
[added, updated, removed, cleared].forEach(evt => {
subscriptions.push(
MeasurementService.subscribe(evt, () => {
debouncedSetDisplayMeasurements(

View File

@ -0,0 +1,25 @@
const commandsModule = ({ servicesManager }) => {
const { MeasurementService } = servicesManager.services;
const actions = {
clearMeasurements: () => {
MeasurementService.clear();
},
};
const definitions = {
clearMeasurements: {
commandFn: actions.clearMeasurements,
storeContexts: [],
options: {},
},
};
return {
actions,
definitions,
defaultContext: 'DEFAULT',
};
};
export default commandsModule;

View File

@ -3,7 +3,7 @@ import { ViewModelContext } from '@ohif/core';
const HelloWorldContext = React.createContext({
message: 'HelloWorldContextTesting',
setMessage: () => {},
setMessage: () => { },
});
HelloWorldContext.displayName = 'HelloWorldContext';

View File

@ -4,6 +4,7 @@ import getLayoutTemplateModule from './getLayoutTemplateModule.js';
import getPanelModule from './getPanelModule.js';
import getSopClassHandlerModule from './getSopClassHandlerModule.js';
import getToolbarModule from './getToolbarModule.js';
import commandsModule from './commandsModule';
import id from './id';
export default {
@ -17,4 +18,7 @@ export default {
getPanelModule,
getSopClassHandlerModule,
getToolbarModule,
getCommandsModule({ servicesManager }) {
return commandsModule({ servicesManager });
},
};

View File

@ -101,9 +101,10 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
const added = MeasurementService.EVENTS.MEASUREMENT_ADDED;
const updated = MeasurementService.EVENTS.MEASUREMENT_UPDATED;
const removed = MeasurementService.EVENTS.MEASUREMENT_REMOVED;
const cleared = MeasurementService.EVENTS.MEASUREMENTS_CLEARED;
const subscriptions = [];
[added, updated, removed].forEach(evt => {
[added, updated, removed, cleared].forEach(evt => {
subscriptions.push(
MeasurementService.subscribe(evt, () => {
setMeasurementsUpdated(Date.now().toString());

View File

@ -62,6 +62,7 @@ export default function mode({ modeConfiguration }) {
'Bidirectional',
'Ellipse',
'Length',
'Clear',
]);
// Could import layout selector here from org.ohif.default (when it exists!)

View File

@ -307,4 +307,19 @@ export default [
type: 'secondary',
},
},
{
id: 'Clear',
type: 'ohif.action',
config: {
groupName: 'primaryTool',
},
props: {
isActive: false,
icon: 'old-trash',
label: 'Clear',
commandName: 'clearMeasurements',
commandOptions: {},
type: 'secondary',
},
},
];

View File

@ -52,6 +52,7 @@ const EVENTS = {
MEASUREMENT_UPDATED: 'event::measurement_updated',
MEASUREMENT_ADDED: 'event::measurement_added',
MEASUREMENT_REMOVED: 'event::measurement_removed',
MEASUREMENTS_CLEARED: 'event::measurements_cleared',
};
const VALUE_TYPES = {
@ -500,6 +501,14 @@ class MeasurementService {
}
}
/**
* Clear all measurements and broadcasts cleared event.
*/
clear() {
this.measurements = {};
this._broadcastChange(this.EVENTS.MEASUREMENTS_CLEARED);
}
/**
* Get measurement mapping function if matching criteria.
*
@ -559,15 +568,27 @@ class MeasurementService {
/**
* Broadcasts measurement changes.
*
* @param {string} measurementId The measurement id
* @param {MeasurementSource} source The measurement source
* @param {string} eventName The event name
* @param {MeasurementSource} source The measurement source
* @param {string} measurement The measurement id
* @return void
*/
_broadcastChange(eventName, source, measurement) {
const hasListeners = Object.keys(this.listeners).length > 0;
const hasCallbacks = Array.isArray(this.listeners[eventName]);
if (!source) {
/* Broadcast to all sources */
/* Object.keys(this.sources).forEach(source => {
if (hasListeners && hasCallbacks) {
this.listeners[eventName].forEach(listener => {
listener.callback({ source, measurement });
});
}
});
return; */
}
if (hasListeners && hasCallbacks) {
this.listeners[eventName].forEach(listener => {
listener.callback({ source, measurement });

View File

@ -0,0 +1,9 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
aria-labelledby="title"
fill="currentColor"
>
<title id="title">Trash</title>
<path d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z" />
</svg>

After

Width:  |  Height:  |  Size: 532 B

View File

@ -57,6 +57,7 @@ import oldDotCircle from './../../assets/icons/old-dot-circle.svg';
import oldAngleLeft from './../../assets/icons/old-angle-left.svg';
import oldReset from './../../assets/icons/old-reset.svg';
import oldCircleO from './../../assets/icons/old-circle-o.svg';
import oldTrash from './../../assets/icons/old-trash.svg';
const ICONS = {
'arrow-down': arrowDown,
@ -114,7 +115,8 @@ const ICONS = {
'old-dot-circle': oldDotCircle,
'old-angle-left': oldAngleLeft,
'old-reset': oldReset,
'old-circle-o': oldCircleO
'old-circle-o': oldCircleO,
'old-trash': oldTrash
};
/**

View File

@ -33,7 +33,7 @@ function appInit(appConfigOrFunc, defaultExtensions) {
/** Used by commands to inject `viewports` from "redux" */
getAppState: () => { },
/** Used by commands to determine active context */
getActiveContexts: () => ['VIEWER', 'ACTIVE_VIEWPORT::CORNERSTONE'],
getActiveContexts: () => ['VIEWER', 'DEFAULT', 'ACTIVE_VIEWPORT::CORNERSTONE'],
};
const servicesManager = new ServicesManager();